ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/channel_mode.c
Revision: 32
Committed: Sun Oct 2 20:41:23 2005 UTC (18 years, 5 months ago) by knight
Content type: text/x-csrc
File size: 46293 byte(s)
Log Message:
- svn:keywords

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

Properties

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