ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/channel_mode.c
Revision: 356
Committed: Mon Jan 2 22:05:15 2006 UTC (18 years, 2 months ago) by adx
Content type: text/x-csrc
File size: 47507 byte(s)
Log Message:
+ MFC support for halfop->op rewriting.

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

Properties

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