ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel_mode.c
Revision: 2892
Committed: Tue Jan 21 18:30:02 2014 UTC (12 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 48952 byte(s)
Log Message:
- channel_mode.c: fixed indentation, removed whitespaces/tabs,
  removed unused header includes

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

Properties

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