ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/channel_mode.c
Revision: 759
Committed: Fri Aug 18 14:29:45 2006 UTC (17 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 48372 byte(s)
Log Message:
- Fixed ban cache as reported by ThaPrince

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->channels.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 chm_hop(client_p, source_p, chptr, parc, parn, parv, errors, alev,
968 dir, c, d, chname);
969 #endif
970 return;
971 }
972
973 #ifdef HALFOPS
974 if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP))
975 {
976 /* promoting from % to @ is visible only to CAP_HOPS servers */
977 mode_changes[mode_count].letter = 'h';
978 mode_changes[mode_count].dir = MODE_DEL;
979 mode_changes[mode_count].caps = caps = CAP_HOPS;
980 mode_changes[mode_count].nocaps = 0;
981 mode_changes[mode_count].mems = ALL_MEMBERS;
982 mode_changes[mode_count].id = NULL;
983 mode_changes[mode_count].arg = targ_p->name;
984 mode_changes[mode_count++].client = targ_p;
985 }
986 #endif
987
988 mode_changes[mode_count].letter = 'o';
989 mode_changes[mode_count].dir = dir;
990 mode_changes[mode_count].caps = caps;
991 mode_changes[mode_count].nocaps = 0;
992 mode_changes[mode_count].mems = ALL_MEMBERS;
993 mode_changes[mode_count].id = targ_p->id;
994 mode_changes[mode_count].arg = targ_p->name;
995 mode_changes[mode_count++].client = targ_p;
996
997 if (dir == MODE_ADD)
998 {
999 AddMemberFlag(member, CHFL_CHANOP);
1000 DelMemberFlag(member, CHFL_DEOPPED | CHFL_HALFOP);
1001 }
1002 else
1003 DelMemberFlag(member, CHFL_CHANOP);
1004 }
1005
1006 #ifdef HALFOPS
1007 static void
1008 chm_hop(struct Client *client_p, struct Client *source_p,
1009 struct Channel *chptr, int parc, int *parn,
1010 char **parv, int *errors, int alev, int dir, char c, void *d,
1011 const char *chname)
1012 {
1013 char *opnick;
1014 struct Client *targ_p;
1015 struct Membership *member;
1016
1017 /* *sigh* - dont allow halfops to set +/-h, they could fully control a
1018 * channel if there were no ops - it doesnt solve anything.. MODE_PRIVATE
1019 * when used with MODE_SECRET is paranoid - cant use +p
1020 *
1021 * it needs to be optional per channel - but not via +p, that or remove
1022 * paranoid.. -- fl_
1023 *
1024 * +p means paranoid, it is useless for anything else on modern IRC, as
1025 * list isn't really usable. If you want to have a private channel these
1026 * days, you set it +s. Halfops can no longer remove simple modes when
1027 * +p is set (although they can set +p) so it is safe to use this to
1028 * control whether they can (de)halfop...
1029 */
1030 if (alev <
1031 ((chptr->mode.mode & MODE_PRIVATE) ? CHACCESS_CHANOP : CHACCESS_HALFOP))
1032 {
1033 if (!(*errors & SM_ERR_NOOPS))
1034 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1035 ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1036 me.name, source_p->name, chname);
1037 *errors |= SM_ERR_NOOPS;
1038 return;
1039 }
1040
1041 if ((dir == MODE_QUERY) || (parc <= *parn))
1042 return;
1043
1044 opnick = parv[(*parn)++];
1045
1046 if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1047 return;
1048 if (!IsClient(targ_p))
1049 return;
1050
1051 if ((member = find_channel_link(targ_p, chptr)) == NULL)
1052 {
1053 if (!(*errors & SM_ERR_NOTONCHANNEL))
1054 sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1055 me.name, source_p->name, opnick, chname);
1056 *errors |= SM_ERR_NOTONCHANNEL;
1057 return;
1058 }
1059
1060 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1061 return;
1062
1063 /* no redundant mode changes */
1064 if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP | CHFL_CHANOP))
1065 return;
1066 if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP))
1067 return;
1068
1069 mode_changes[mode_count].letter = 'h';
1070 mode_changes[mode_count].dir = dir;
1071 mode_changes[mode_count].caps = CAP_HOPS;
1072 mode_changes[mode_count].nocaps = 0;
1073 mode_changes[mode_count].mems = ALL_MEMBERS;
1074 mode_changes[mode_count].id = targ_p->id;
1075 mode_changes[mode_count].arg = targ_p->name;
1076 mode_changes[mode_count++].client = targ_p;
1077
1078 mode_changes[mode_count].letter = 'o';
1079 mode_changes[mode_count].dir = dir;
1080 mode_changes[mode_count].caps = 0;
1081 mode_changes[mode_count].nocaps = CAP_HOPS;
1082 mode_changes[mode_count].mems = ONLY_SERVERS;
1083 mode_changes[mode_count].id = targ_p->id;
1084 mode_changes[mode_count].arg = targ_p->name;
1085 mode_changes[mode_count++].client = targ_p;
1086
1087 if (dir == MODE_ADD)
1088 {
1089 AddMemberFlag(member, CHFL_HALFOP);
1090 DelMemberFlag(member, CHFL_DEOPPED);
1091 }
1092 else
1093 DelMemberFlag(member, CHFL_HALFOP);
1094 }
1095 #endif
1096
1097 static void
1098 chm_voice(struct Client *client_p, struct Client *source_p,
1099 struct Channel *chptr, int parc, int *parn,
1100 char **parv, int *errors, int alev, int dir, char c, void *d,
1101 const char *chname)
1102 {
1103 char *opnick;
1104 struct Client *targ_p;
1105 struct Membership *member;
1106
1107 if (alev < CHACCESS_HALFOP)
1108 {
1109 if (!(*errors & SM_ERR_NOOPS))
1110 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1111 ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1112 me.name, source_p->name, chname);
1113 *errors |= SM_ERR_NOOPS;
1114 return;
1115 }
1116
1117 if ((dir == MODE_QUERY) || parc <= *parn)
1118 return;
1119
1120 opnick = parv[(*parn)++];
1121
1122 if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1123 return;
1124 if (!IsClient(targ_p))
1125 return;
1126
1127 if ((member = find_channel_link(targ_p, chptr)) == NULL)
1128 {
1129 if (!(*errors & SM_ERR_NOTONCHANNEL))
1130 sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1131 me.name, source_p->name, opnick, chname);
1132 *errors |= SM_ERR_NOTONCHANNEL;
1133 return;
1134 }
1135
1136 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1137 return;
1138
1139 /* no redundant mode changes */
1140 if (dir == MODE_ADD && has_member_flags(member, CHFL_VOICE))
1141 return;
1142 if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
1143 return;
1144
1145 mode_changes[mode_count].letter = 'v';
1146 mode_changes[mode_count].dir = dir;
1147 mode_changes[mode_count].caps = 0;
1148 mode_changes[mode_count].nocaps = 0;
1149 mode_changes[mode_count].mems = ALL_MEMBERS;
1150 mode_changes[mode_count].id = targ_p->id;
1151 mode_changes[mode_count].arg = targ_p->name;
1152 mode_changes[mode_count++].client = targ_p;
1153
1154 if (dir == MODE_ADD)
1155 AddMemberFlag(member, CHFL_VOICE);
1156 else
1157 DelMemberFlag(member, CHFL_VOICE);
1158 }
1159
1160 static void
1161 chm_limit(struct Client *client_p, struct Client *source_p,
1162 struct Channel *chptr, int parc, int *parn,
1163 char **parv, int *errors, int alev, int dir, char c, void *d,
1164 const char *chname)
1165 {
1166 int i, limit;
1167 char *lstr;
1168
1169 if (alev < CHACCESS_HALFOP)
1170 {
1171 if (!(*errors & SM_ERR_NOOPS))
1172 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1173 ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1174 me.name, source_p->name, chname);
1175 *errors |= SM_ERR_NOOPS;
1176 return;
1177 }
1178
1179 if (dir == MODE_QUERY)
1180 return;
1181
1182 if ((dir == MODE_ADD) && parc > *parn)
1183 {
1184 lstr = parv[(*parn)++];
1185
1186 if ((limit = atoi(lstr)) <= 0)
1187 return;
1188
1189 ircsprintf(lstr, "%d", limit);
1190
1191 /* if somebody sets MODE #channel +ll 1 2, accept latter --fl */
1192 for (i = 0; i < mode_count; i++)
1193 {
1194 if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1195 mode_changes[i].letter = 0;
1196 }
1197
1198 mode_changes[mode_count].letter = c;
1199 mode_changes[mode_count].dir = MODE_ADD;
1200 mode_changes[mode_count].caps = 0;
1201 mode_changes[mode_count].nocaps = 0;
1202 mode_changes[mode_count].mems = ALL_MEMBERS;
1203 mode_changes[mode_count].id = NULL;
1204 mode_changes[mode_count++].arg = lstr;
1205
1206 chptr->mode.limit = limit;
1207 }
1208 else if (dir == MODE_DEL)
1209 {
1210 if (!chptr->mode.limit)
1211 return;
1212
1213 chptr->mode.limit = 0;
1214
1215 mode_changes[mode_count].letter = c;
1216 mode_changes[mode_count].dir = MODE_DEL;
1217 mode_changes[mode_count].caps = 0;
1218 mode_changes[mode_count].nocaps = 0;
1219 mode_changes[mode_count].mems = ALL_MEMBERS;
1220 mode_changes[mode_count].id = NULL;
1221 mode_changes[mode_count++].arg = NULL;
1222 }
1223 }
1224
1225 static void
1226 chm_key(struct Client *client_p, struct Client *source_p,
1227 struct Channel *chptr, int parc, int *parn,
1228 char **parv, int *errors, int alev, int dir, char c, void *d,
1229 const char *chname)
1230 {
1231 int i;
1232 char *key;
1233
1234 if (alev < CHACCESS_HALFOP)
1235 {
1236 if (!(*errors & SM_ERR_NOOPS))
1237 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1238 ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1239 me.name, source_p->name, chname);
1240 *errors |= SM_ERR_NOOPS;
1241 return;
1242 }
1243
1244 if (dir == MODE_QUERY)
1245 return;
1246
1247 if ((dir == MODE_ADD) && parc > *parn)
1248 {
1249 key = parv[(*parn)++];
1250
1251 if (MyClient(source_p))
1252 fix_key(key);
1253 else
1254 fix_key_old(key);
1255
1256 if (*key == '\0')
1257 return;
1258
1259 assert(key[0] != ' ');
1260 strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
1261
1262 /* if somebody does MODE #channel +kk a b, accept latter --fl */
1263 for (i = 0; i < mode_count; i++)
1264 {
1265 if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1266 mode_changes[i].letter = 0;
1267 }
1268
1269 mode_changes[mode_count].letter = c;
1270 mode_changes[mode_count].dir = MODE_ADD;
1271 mode_changes[mode_count].caps = 0;
1272 mode_changes[mode_count].nocaps = 0;
1273 mode_changes[mode_count].mems = ALL_MEMBERS;
1274 mode_changes[mode_count].id = NULL;
1275 mode_changes[mode_count++].arg = chptr->mode.key;
1276 }
1277 else if (dir == MODE_DEL)
1278 {
1279 if (parc > *parn)
1280 (*parn)++;
1281
1282 if (chptr->mode.key[0] == '\0')
1283 return;
1284
1285 chptr->mode.key[0] = '\0';
1286
1287 mode_changes[mode_count].letter = c;
1288 mode_changes[mode_count].dir = MODE_DEL;
1289 mode_changes[mode_count].caps = 0;
1290 mode_changes[mode_count].nocaps = 0;
1291 mode_changes[mode_count].mems = ALL_MEMBERS;
1292 mode_changes[mode_count].id = NULL;
1293 mode_changes[mode_count++].arg = "*";
1294 }
1295 }
1296
1297 struct ChannelMode
1298 {
1299 void (*func) (struct Client *client_p, struct Client *source_p,
1300 struct Channel *chptr, int parc, int *parn, char **parv,
1301 int *errors, int alev, int dir, char c, void *d,
1302 const char *chname);
1303 void *d;
1304 };
1305
1306 /* *INDENT-OFF* */
1307 static struct ChannelMode ModeTable[255] =
1308 {
1309 {chm_nosuch, NULL},
1310 {chm_nosuch, NULL}, /* A */
1311 {chm_nosuch, NULL}, /* B */
1312 {chm_nosuch, NULL}, /* C */
1313 {chm_nosuch, NULL}, /* D */
1314 {chm_nosuch, NULL}, /* E */
1315 {chm_nosuch, NULL}, /* F */
1316 {chm_nosuch, NULL}, /* G */
1317 {chm_nosuch, NULL}, /* H */
1318 {chm_invex, NULL}, /* I */
1319 {chm_nosuch, NULL}, /* J */
1320 {chm_nosuch, NULL}, /* K */
1321 {chm_nosuch, NULL}, /* L */
1322 {chm_nosuch, NULL}, /* M */
1323 {chm_nosuch, NULL}, /* N */
1324 {chm_nosuch, NULL}, /* O */
1325 {chm_nosuch, NULL}, /* P */
1326 {chm_nosuch, NULL}, /* Q */
1327 {chm_nosuch, NULL}, /* R */
1328 {chm_nosuch, NULL}, /* S */
1329 {chm_nosuch, NULL}, /* T */
1330 {chm_nosuch, NULL}, /* U */
1331 {chm_nosuch, NULL}, /* V */
1332 {chm_nosuch, NULL}, /* W */
1333 {chm_nosuch, NULL}, /* X */
1334 {chm_nosuch, NULL}, /* Y */
1335 {chm_nosuch, NULL}, /* Z */
1336 {chm_nosuch, NULL},
1337 {chm_nosuch, NULL},
1338 {chm_nosuch, NULL},
1339 {chm_nosuch, NULL},
1340 {chm_nosuch, NULL},
1341 {chm_nosuch, NULL},
1342 {chm_nosuch, NULL}, /* a */
1343 {chm_ban, NULL}, /* b */
1344 {chm_nosuch, NULL}, /* c */
1345 {chm_nosuch, NULL}, /* d */
1346 {chm_except, NULL}, /* e */
1347 {chm_nosuch, NULL}, /* f */
1348 {chm_nosuch, NULL}, /* g */
1349 #ifdef HALFOPS
1350 {chm_hop, NULL}, /* h */
1351 #else
1352 {chm_nosuch, NULL}, /* h */
1353 #endif
1354 {chm_simple, (void *) MODE_INVITEONLY}, /* i */
1355 {chm_nosuch, NULL}, /* j */
1356 {chm_key, NULL}, /* k */
1357 {chm_limit, NULL}, /* l */
1358 {chm_simple, (void *) MODE_MODERATED}, /* m */
1359 {chm_simple, (void *) MODE_NOPRIVMSGS}, /* n */
1360 {chm_op, NULL}, /* o */
1361 {chm_simple, (void *) MODE_PRIVATE}, /* p */
1362 {chm_nosuch, NULL}, /* q */
1363 {chm_nosuch, NULL}, /* r */
1364 {chm_simple, (void *) MODE_SECRET}, /* s */
1365 {chm_simple, (void *) MODE_TOPICLIMIT}, /* t */
1366 {chm_nosuch, NULL}, /* u */
1367 {chm_voice, NULL}, /* v */
1368 {chm_nosuch, NULL}, /* w */
1369 {chm_nosuch, NULL}, /* x */
1370 {chm_nosuch, NULL}, /* y */
1371 {chm_nosuch, NULL}, /* z */
1372 };
1373 /* *INDENT-ON* */
1374
1375 /* get_channel_access()
1376 *
1377 * inputs - pointer to Client struct
1378 * - pointer to Membership struct
1379 * output - CHACCESS_CHANOP if we should let them have
1380 * chanop level access, 0 for peon level access.
1381 * side effects - NONE
1382 */
1383 static int
1384 get_channel_access(struct Client *source_p, struct Membership *member)
1385 {
1386 /* Let hacked servers in for now... */
1387 if (!MyClient(source_p))
1388 return CHACCESS_CHANOP;
1389
1390 if (member == NULL)
1391 return CHACCESS_NOTONCHAN;
1392
1393 /* just to be sure.. */
1394 assert(source_p == member->client_p);
1395
1396 if (has_member_flags(member, CHFL_CHANOP))
1397 return CHACCESS_CHANOP;
1398
1399 #ifdef HALFOPS
1400 if (has_member_flags(member, CHFL_HALFOP))
1401 return CHACCESS_HALFOP;
1402 #endif
1403
1404 return CHACCESS_PEON;
1405 }
1406
1407 /* void send_cap_mode_changes(struct Client *client_p,
1408 * struct Client *source_p,
1409 * struct Channel *chptr, int cap, int nocap)
1410 * Input: The client sending(client_p), the source client(source_p),
1411 * the channel to send mode changes for(chptr)
1412 * Output: None.
1413 * Side-effects: Sends the appropriate mode changes to capable servers.
1414 *
1415 * send_cap_mode_changes() will loop the server list itself, because
1416 * at this point in time we have 4 capabs for channels, CAP_IE, CAP_EX,
1417 * and a server could support any number of these..
1418 * so we make the modebufs per server, tailoring them to each servers
1419 * specific demand. Its not very pretty, but its one of the few realistic
1420 * ways to handle having this many capabs for channel modes.. --fl_
1421 *
1422 * Reverted back to my original design, except that we now keep a count
1423 * of the number of servers which each combination as an optimisation, so
1424 * the capabs combinations which are not needed are not worked out. -A1kmm
1425 */
1426 /* rewritten to ensure parabuf < MODEBUFLEN -db */
1427
1428 static void
1429 send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1430 struct Channel *chptr, int cap, int nocap)
1431 {
1432 int i, mbl, pbl, arglen, nc, mc;
1433 int len;
1434 const char *arg = NULL;
1435 char *parptr;
1436 int dir = MODE_QUERY;
1437
1438 mc = 0;
1439 nc = 0;
1440 pbl = 0;
1441
1442 parabuf[0] = '\0';
1443 parptr = parabuf;
1444
1445 if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1446 mbl = ircsprintf(modebuf, ":%s TMODE %lu %s ", source_p->id,
1447 (unsigned long)chptr->channelts, chptr->chname);
1448 else
1449 mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
1450 chptr->chname);
1451
1452 /* loop the list of - modes we have */
1453 for (i = 0; i < mode_count; i++)
1454 {
1455 /* if they dont support the cap we need, or they do support a cap they
1456 * cant have, then dont add it to the modebuf.. that way they wont see
1457 * the mode
1458 */
1459 if ((mode_changes[i].letter == 0) ||
1460 ((cap & mode_changes[i].caps) != mode_changes[i].caps)
1461 || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
1462 continue;
1463
1464 arg = "";
1465
1466 if ((cap & CAP_TS6) && mode_changes[i].id)
1467 arg = mode_changes[i].id;
1468 if (*arg == '\0')
1469 arg = mode_changes[i].arg;
1470
1471 /* if we're creeping past the buf size, we need to send it and make
1472 * another line for the other modes
1473 * XXX - this could give away server topology with uids being
1474 * different lengths, but not much we can do, except possibly break
1475 * them as if they were the longest of the nick or uid at all times,
1476 * which even then won't work as we don't always know the uid -A1kmm.
1477 */
1478 if (arg != NULL)
1479 arglen = strlen(arg);
1480 else
1481 arglen = 0;
1482
1483 if ((mc == MAXMODEPARAMS) ||
1484 ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1485 (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN)
1486 {
1487 if (nc != 0)
1488 sendto_server(client_p, source_p, chptr, cap, nocap,
1489 LL_ICHAN | LL_ICLIENT, "%s %s",
1490 modebuf, parabuf);
1491 nc = 0;
1492 mc = 0;
1493
1494 if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1495 mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->id,
1496 chptr->chname);
1497 else
1498 mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
1499 chptr->chname);
1500
1501 pbl = 0;
1502 parabuf[0] = '\0';
1503 parptr = parabuf;
1504 dir = MODE_QUERY;
1505 }
1506
1507 if (dir != mode_changes[i].dir)
1508 {
1509 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1510 dir = mode_changes[i].dir;
1511 }
1512
1513 modebuf[mbl++] = mode_changes[i].letter;
1514 modebuf[mbl] = '\0';
1515 nc++;
1516
1517 if (arg != NULL)
1518 {
1519 len = ircsprintf(parptr, "%s ", arg);
1520 pbl += len;
1521 parptr += len;
1522 mc++;
1523 }
1524 }
1525
1526 if (pbl && parabuf[pbl - 1] == ' ')
1527 parabuf[pbl - 1] = 0;
1528
1529 if (nc != 0)
1530 sendto_server(client_p, source_p, chptr, cap, nocap,
1531 LL_ICLIENT, "%s %s", modebuf, parabuf);
1532 }
1533
1534 /* void send_mode_changes(struct Client *client_p,
1535 * struct Client *source_p,
1536 * struct Channel *chptr)
1537 * Input: The client sending(client_p), the source client(source_p),
1538 * the channel to send mode changes for(chptr),
1539 * mode change globals.
1540 * Output: None.
1541 * Side-effects: Sends the appropriate mode changes to other clients
1542 * and propagates to servers.
1543 */
1544 /* ensure parabuf < MODEBUFLEN -db */
1545 static void
1546 send_mode_changes(struct Client *client_p, struct Client *source_p,
1547 struct Channel *chptr, char *chname)
1548 {
1549 int i, mbl, pbl, arglen, nc, mc;
1550 int len;
1551 const char *arg = NULL;
1552 char *parptr;
1553 int dir = MODE_QUERY;
1554
1555 /* bail out if we have nothing to do... */
1556 if (!mode_count)
1557 return;
1558
1559 if (IsServer(source_p))
1560 mbl = ircsprintf(modebuf, ":%s MODE %s ", (IsHidden(source_p) ||
1561 ConfigServerHide.hide_servers) ?
1562 me.name : source_p->name, chname);
1563 else
1564 mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1565 source_p->username, source_p->host, chname);
1566
1567 mc = 0;
1568 nc = 0;
1569 pbl = 0;
1570
1571 parabuf[0] = '\0';
1572 parptr = parabuf;
1573
1574 for (i = 0; i < mode_count; i++)
1575 {
1576 if (mode_changes[i].letter == 0 ||
1577 mode_changes[i].mems == NON_CHANOPS ||
1578 mode_changes[i].mems == ONLY_SERVERS)
1579 continue;
1580
1581 arg = mode_changes[i].arg;
1582 if (arg != NULL)
1583 arglen = strlen(arg);
1584 else
1585 arglen = 0;
1586
1587 if ((mc == MAXMODEPARAMS) ||
1588 ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1589 ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
1590 {
1591 if (mbl && modebuf[mbl - 1] == '-')
1592 modebuf[mbl - 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 if (IsServer(source_p))
1601 mbl = ircsprintf(modebuf, ":%s MODE %s ", me.name, chname);
1602 else
1603 mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1604 source_p->username, source_p->host, chname);
1605
1606 pbl = 0;
1607 parabuf[0] = '\0';
1608 parptr = parabuf;
1609 dir = MODE_QUERY;
1610 }
1611
1612 if (dir != mode_changes[i].dir)
1613 {
1614 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1615 dir = mode_changes[i].dir;
1616 }
1617
1618 modebuf[mbl++] = mode_changes[i].letter;
1619 modebuf[mbl] = '\0';
1620 nc++;
1621
1622 if (arg != NULL)
1623 {
1624 len = ircsprintf(parptr, "%s ", arg);
1625 pbl += len;
1626 parptr += len;
1627 mc++;
1628 }
1629 }
1630
1631 if (pbl && parabuf[pbl - 1] == ' ')
1632 parabuf[pbl - 1] = 0;
1633
1634 if (nc != 0)
1635 sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1636
1637 nc = 0;
1638 mc = 0;
1639
1640 /* Now send to servers... */
1641 for (i = 0; i < NCHCAP_COMBOS; i++)
1642 if (chcap_combos[i].count != 0)
1643 send_cap_mode_changes(client_p, source_p, chptr,
1644 chcap_combos[i].cap_yes,
1645 chcap_combos[i].cap_no);
1646 }
1647
1648 /* void set_channel_mode(struct Client *client_p, struct Client *source_p,
1649 * struct Channel *chptr, int parc, char **parv,
1650 * char *chname)
1651 * Input: The client we received this from, the client this originated
1652 * from, the channel, the parameter count starting at the modes,
1653 * the parameters, the channel name.
1654 * Output: None.
1655 * Side-effects: Changes the channel membership and modes appropriately,
1656 * sends the appropriate MODE messages to the appropriate
1657 * clients.
1658 */
1659 void
1660 set_channel_mode(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
1661 struct Membership *member, int parc, char *parv[], char *chname)
1662 {
1663 int dir = MODE_ADD;
1664 int parn = 1;
1665 int alevel, errors = 0;
1666 char *ml = parv[0], c;
1667 int table_position;
1668
1669 mode_count = 0;
1670 mode_limit = 0;
1671 simple_modes_mask = 0;
1672
1673 alevel = get_channel_access(source_p, member);
1674
1675 for (; (c = *ml) != '\0'; ml++)
1676 {
1677 #if 0
1678 if(mode_count > 20)
1679 break;
1680 #endif
1681 switch (c)
1682 {
1683 case '+':
1684 dir = MODE_ADD;
1685 break;
1686 case '-':
1687 dir = MODE_DEL;
1688 break;
1689 case '=':
1690 dir = MODE_QUERY;
1691 break;
1692 default:
1693 if (c < 'A' || c > 'z')
1694 table_position = 0;
1695 else
1696 table_position = c - 'A' + 1;
1697 ModeTable[table_position].func(client_p, source_p, chptr,
1698 parc, &parn,
1699 parv, &errors, alevel, dir, c,
1700 ModeTable[table_position].d,
1701 chname);
1702 break;
1703 }
1704 }
1705
1706 send_mode_changes(client_p, source_p, chptr, chname);
1707 }

Properties

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