ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel_mode.c
Revision: 931
Committed: Fri May 30 04:05:57 2008 UTC (17 years, 3 months ago) by db
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/channel_mode.c
File size: 48343 byte(s)
Log Message:
- bug fix by caf <kevin@sylandro.com>


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

Properties

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