ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/channel_mode.c
Revision: 593
Committed: Fri May 12 05:47:32 2006 UTC (17 years, 10 months ago) by michael
Content type: text/x-csrc
File size: 48138 byte(s)
Log Message:
- Backported RKLINE fix so the user and host portion of a banmask don't get
  cut off after 10 and 63 chars, respectively.
  A split_nuh() rewrite was required for this.
- Removed now unused xstrldup() function

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

Properties

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