]> jfr.im git - solanum.git/blob - src/channel.c
src/s_conf: More detailed error messages conforming to POSIX errno
[solanum.git] / src / channel.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * channel.c: Controls channels.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 *
24 * $Id: channel.c 3580 2007-11-07 23:45:14Z jilles $
25 */
26
27 #include "stdinc.h"
28 #include "channel.h"
29 #include "chmode.h"
30 #include "client.h"
31 #include "common.h"
32 #include "hash.h"
33 #include "hook.h"
34 #include "match.h"
35 #include "ircd.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 "s_newconf.h"
43 #include "logger.h"
44 #include "ipv4_from_ipv6.h"
45
46 struct config_channel_entry ConfigChannel;
47 rb_dlink_list global_channel_list;
48 static rb_bh *channel_heap;
49 static rb_bh *ban_heap;
50 static rb_bh *topic_heap;
51 static rb_bh *member_heap;
52
53 static void free_topic(struct Channel *chptr);
54
55 static int h_can_join;
56 static int h_can_send;
57 int h_get_channel_access;
58
59 /* init_channels()
60 *
61 * input -
62 * output -
63 * side effects - initialises the various blockheaps
64 */
65 void
66 init_channels(void)
67 {
68 channel_heap = rb_bh_create(sizeof(struct Channel), CHANNEL_HEAP_SIZE, "channel_heap");
69 ban_heap = rb_bh_create(sizeof(struct Ban), BAN_HEAP_SIZE, "ban_heap");
70 topic_heap = rb_bh_create(TOPICLEN + 1 + USERHOST_REPLYLEN, TOPIC_HEAP_SIZE, "topic_heap");
71 member_heap = rb_bh_create(sizeof(struct membership), MEMBER_HEAP_SIZE, "member_heap");
72
73 h_can_join = register_hook("can_join");
74 h_can_send = register_hook("can_send");
75 h_get_channel_access = register_hook("get_channel_access");
76 }
77
78 /*
79 * allocate_channel - Allocates a channel
80 */
81 struct Channel *
82 allocate_channel(const char *chname)
83 {
84 struct Channel *chptr;
85 chptr = rb_bh_alloc(channel_heap);
86 chptr->chname = rb_strdup(chname);
87 return (chptr);
88 }
89
90 void
91 free_channel(struct Channel *chptr)
92 {
93 rb_free(chptr->chname);
94 rb_free(chptr->mode_lock);
95 rb_bh_free(channel_heap, chptr);
96 }
97
98 struct Ban *
99 allocate_ban(const char *banstr, const char *who, const char *forward)
100 {
101 struct Ban *bptr;
102 bptr = rb_bh_alloc(ban_heap);
103 bptr->banstr = rb_strdup(banstr);
104 bptr->who = rb_strdup(who);
105 bptr->forward = forward ? rb_strdup(forward) : NULL;
106
107 return (bptr);
108 }
109
110 void
111 free_ban(struct Ban *bptr)
112 {
113 rb_free(bptr->banstr);
114 rb_free(bptr->who);
115 rb_free(bptr->forward);
116 rb_bh_free(ban_heap, bptr);
117 }
118
119 /*
120 * send_channel_join()
121 *
122 * input - channel to join, client joining.
123 * output - none
124 * side effects - none
125 */
126 void
127 send_channel_join(struct Channel *chptr, struct Client *client_p)
128 {
129 if (!IsClient(client_p))
130 return;
131
132 sendto_channel_local_with_capability(ALL_MEMBERS, NOCAPS, CLICAP_EXTENDED_JOIN, chptr, ":%s!%s@%s JOIN %s",
133 client_p->name, client_p->username, client_p->host, chptr->chname);
134
135 sendto_channel_local_with_capability(ALL_MEMBERS, CLICAP_EXTENDED_JOIN, NOCAPS, chptr, ":%s!%s@%s JOIN %s %s :%s",
136 client_p->name, client_p->username, client_p->host, chptr->chname,
137 EmptyString(client_p->user->suser) ? "*" : client_p->user->suser,
138 client_p->info);
139
140 /* Send away message to away-notify enabled clients. */
141 if (client_p->user->away)
142 sendto_channel_local_with_capability_butone(client_p, ALL_MEMBERS, CLICAP_AWAY_NOTIFY, NOCAPS, chptr,
143 ":%s!%s@%s AWAY :%s", client_p->name, client_p->username,
144 client_p->host, client_p->user->away);
145 }
146
147 /* find_channel_membership()
148 *
149 * input - channel to find them in, client to find
150 * output - membership of client in channel, else NULL
151 * side effects -
152 */
153 struct membership *
154 find_channel_membership(struct Channel *chptr, struct Client *client_p)
155 {
156 struct membership *msptr;
157 rb_dlink_node *ptr;
158
159 if(!IsClient(client_p))
160 return NULL;
161
162 /* Pick the most efficient list to use to be nice to things like
163 * CHANSERV which could be in a large number of channels
164 */
165 if(rb_dlink_list_length(&chptr->members) < rb_dlink_list_length(&client_p->user->channel))
166 {
167 RB_DLINK_FOREACH(ptr, chptr->members.head)
168 {
169 msptr = ptr->data;
170
171 if(msptr->client_p == client_p)
172 return msptr;
173 }
174 }
175 else
176 {
177 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
178 {
179 msptr = ptr->data;
180
181 if(msptr->chptr == chptr)
182 return msptr;
183 }
184 }
185
186 return NULL;
187 }
188
189 /* find_channel_status()
190 *
191 * input - membership to get status for, whether we can combine flags
192 * output - flags of user on channel
193 * side effects -
194 */
195 const char *
196 find_channel_status(struct membership *msptr, int combine)
197 {
198 static char buffer[3];
199 char *p;
200
201 p = buffer;
202
203 if(is_chanop(msptr))
204 {
205 if(!combine)
206 return "@";
207 *p++ = '@';
208 }
209
210 if(is_voiced(msptr))
211 *p++ = '+';
212
213 *p = '\0';
214 return buffer;
215 }
216
217 /* add_user_to_channel()
218 *
219 * input - channel to add client to, client to add, channel flags
220 * output -
221 * side effects - user is added to channel
222 */
223 void
224 add_user_to_channel(struct Channel *chptr, struct Client *client_p, int flags)
225 {
226 struct membership *msptr;
227
228 s_assert(client_p->user != NULL);
229 if(client_p->user == NULL)
230 return;
231
232 msptr = rb_bh_alloc(member_heap);
233
234 msptr->chptr = chptr;
235 msptr->client_p = client_p;
236 msptr->flags = flags;
237
238 rb_dlinkAdd(msptr, &msptr->usernode, &client_p->user->channel);
239 rb_dlinkAdd(msptr, &msptr->channode, &chptr->members);
240
241 if(MyClient(client_p))
242 rb_dlinkAdd(msptr, &msptr->locchannode, &chptr->locmembers);
243 }
244
245 /* remove_user_from_channel()
246 *
247 * input - membership pointer to remove from channel
248 * output -
249 * side effects - membership (thus user) is removed from channel
250 */
251 void
252 remove_user_from_channel(struct membership *msptr)
253 {
254 struct Client *client_p;
255 struct Channel *chptr;
256 s_assert(msptr != NULL);
257 if(msptr == NULL)
258 return;
259
260 client_p = msptr->client_p;
261 chptr = msptr->chptr;
262
263 rb_dlinkDelete(&msptr->usernode, &client_p->user->channel);
264 rb_dlinkDelete(&msptr->channode, &chptr->members);
265
266 if(client_p->servptr == &me)
267 rb_dlinkDelete(&msptr->locchannode, &chptr->locmembers);
268
269 if(!(chptr->mode.mode & MODE_PERMANENT) && rb_dlink_list_length(&chptr->members) <= 0)
270 destroy_channel(chptr);
271
272 rb_bh_free(member_heap, msptr);
273
274 return;
275 }
276
277 /* remove_user_from_channels()
278 *
279 * input - user to remove from all channels
280 * output -
281 * side effects - user is removed from all channels
282 */
283 void
284 remove_user_from_channels(struct Client *client_p)
285 {
286 struct Channel *chptr;
287 struct membership *msptr;
288 rb_dlink_node *ptr;
289 rb_dlink_node *next_ptr;
290
291 if(client_p == NULL)
292 return;
293
294 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->user->channel.head)
295 {
296 msptr = ptr->data;
297 chptr = msptr->chptr;
298
299 rb_dlinkDelete(&msptr->channode, &chptr->members);
300
301 if(client_p->servptr == &me)
302 rb_dlinkDelete(&msptr->locchannode, &chptr->locmembers);
303
304 if(!(chptr->mode.mode & MODE_PERMANENT) && rb_dlink_list_length(&chptr->members) <= 0)
305 destroy_channel(chptr);
306
307 rb_bh_free(member_heap, msptr);
308 }
309
310 client_p->user->channel.head = client_p->user->channel.tail = NULL;
311 client_p->user->channel.length = 0;
312 }
313
314 /* invalidate_bancache_user()
315 *
316 * input - user to invalidate ban cache for
317 * output -
318 * side effects - ban cache is invalidated for all memberships of that user
319 * to be used after a nick change
320 */
321 void
322 invalidate_bancache_user(struct Client *client_p)
323 {
324 struct membership *msptr;
325 rb_dlink_node *ptr;
326
327 if(client_p == NULL)
328 return;
329
330 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
331 {
332 msptr = ptr->data;
333 msptr->bants = 0;
334 msptr->flags &= ~CHFL_BANNED;
335 }
336 }
337
338 /* check_channel_name()
339 *
340 * input - channel name
341 * output - 1 if valid channel name, else 0
342 * side effects -
343 */
344 int
345 check_channel_name(const char *name)
346 {
347 s_assert(name != NULL);
348 if(name == NULL)
349 return 0;
350
351 for (; *name; ++name)
352 {
353 if(!IsChanChar(*name))
354 return 0;
355 }
356
357 return 1;
358 }
359
360 /* free_channel_list()
361 *
362 * input - rb_dlink list to free
363 * output -
364 * side effects - list of b/e/I modes is cleared
365 */
366 void
367 free_channel_list(rb_dlink_list * list)
368 {
369 rb_dlink_node *ptr;
370 rb_dlink_node *next_ptr;
371 struct Ban *actualBan;
372
373 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
374 {
375 actualBan = ptr->data;
376 free_ban(actualBan);
377 }
378
379 list->head = list->tail = NULL;
380 list->length = 0;
381 }
382
383 /* destroy_channel()
384 *
385 * input - channel to destroy
386 * output -
387 * side effects - channel is obliterated
388 */
389 void
390 destroy_channel(struct Channel *chptr)
391 {
392 rb_dlink_node *ptr, *next_ptr;
393
394 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
395 {
396 del_invite(chptr, ptr->data);
397 }
398
399 /* free all bans/exceptions/denies */
400 free_channel_list(&chptr->banlist);
401 free_channel_list(&chptr->exceptlist);
402 free_channel_list(&chptr->invexlist);
403 free_channel_list(&chptr->quietlist);
404
405 /* Free the topic */
406 free_topic(chptr);
407
408 rb_dlinkDelete(&chptr->node, &global_channel_list);
409 del_from_channel_hash(chptr->chname, chptr);
410 free_channel(chptr);
411 }
412
413 /* channel_pub_or_secret()
414 *
415 * input - channel
416 * output - "=" if public, "@" if secret, else "*"
417 * side effects -
418 */
419 static const char *
420 channel_pub_or_secret(struct Channel *chptr)
421 {
422 if(PubChannel(chptr))
423 return ("=");
424 else if(SecretChannel(chptr))
425 return ("@");
426 return ("*");
427 }
428
429 /* channel_member_names()
430 *
431 * input - channel to list, client to list to, show endofnames
432 * output -
433 * side effects - client is given list of users on channel
434 */
435 void
436 channel_member_names(struct Channel *chptr, struct Client *client_p, int show_eon)
437 {
438 struct membership *msptr;
439 struct Client *target_p;
440 rb_dlink_node *ptr;
441 char lbuf[BUFSIZE];
442 char *t;
443 int mlen;
444 int tlen;
445 int cur_len;
446 int is_member;
447 int stack = IsCapable(client_p, CLICAP_MULTI_PREFIX);
448
449 if(ShowChannel(client_p, chptr))
450 {
451 is_member = IsMember(client_p, chptr);
452
453 cur_len = mlen = rb_sprintf(lbuf, form_str(RPL_NAMREPLY),
454 me.name, client_p->name,
455 channel_pub_or_secret(chptr), chptr->chname);
456
457 t = lbuf + cur_len;
458
459 RB_DLINK_FOREACH(ptr, chptr->members.head)
460 {
461 msptr = ptr->data;
462 target_p = msptr->client_p;
463
464 if(IsInvisible(target_p) && !is_member)
465 continue;
466
467 /* space, possible "@+" prefix */
468 if(cur_len + strlen(target_p->name) + 3 >= BUFSIZE - 3)
469 {
470 *(t - 1) = '\0';
471 sendto_one(client_p, "%s", lbuf);
472 cur_len = mlen;
473 t = lbuf + mlen;
474 }
475
476 tlen = rb_sprintf(t, "%s%s ", find_channel_status(msptr, stack),
477 target_p->name);
478
479 cur_len += tlen;
480 t += tlen;
481 }
482
483 /* The old behaviour here was to always output our buffer,
484 * even if there are no clients we can show. This happens
485 * when a client does "NAMES" with no parameters, and all
486 * the clients on a -sp channel are +i. I dont see a good
487 * reason for keeping that behaviour, as it just wastes
488 * bandwidth. --anfl
489 */
490 if(cur_len != mlen)
491 {
492 *(t - 1) = '\0';
493 sendto_one(client_p, "%s", lbuf);
494 }
495 }
496
497 if(show_eon)
498 sendto_one(client_p, form_str(RPL_ENDOFNAMES),
499 me.name, client_p->name, chptr->chname);
500 }
501
502 /* del_invite()
503 *
504 * input - channel to remove invite from, client to remove
505 * output -
506 * side effects - user is removed from invite list, if exists
507 */
508 void
509 del_invite(struct Channel *chptr, struct Client *who)
510 {
511 rb_dlinkFindDestroy(who, &chptr->invites);
512 rb_dlinkFindDestroy(chptr, &who->user->invited);
513 }
514
515 /* is_banned_list()
516 *
517 * input - channel to check bans for, ban list (banlist or quietlist),
518 * user to check bans against, optional prebuilt buffers,
519 * optional forward channel pointer
520 * output - 1 if banned, else 0
521 * side effects -
522 */
523 static int
524 is_banned_list(struct Channel *chptr, rb_dlink_list *list,
525 struct Client *who, struct membership *msptr,
526 const char *s, const char *s2, const char **forward)
527 {
528 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
529 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
530 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
531 char src_ip4host[NICKLEN + USERLEN + HOSTLEN + 6];
532 char *s3 = NULL;
533 char *s4 = NULL;
534 struct sockaddr_in ip4;
535 rb_dlink_node *ptr;
536 struct Ban *actualBan = NULL;
537 struct Ban *actualExcept = NULL;
538
539 if(!MyClient(who))
540 return 0;
541
542 /* if the buffers havent been built, do it here */
543 if(s == NULL)
544 {
545 rb_sprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
546 rb_sprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
547
548 s = src_host;
549 s2 = src_iphost;
550 }
551 if(who->localClient->mangledhost != NULL)
552 {
553 /* if host mangling mode enabled, also check their real host */
554 if(!strcmp(who->host, who->localClient->mangledhost))
555 {
556 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
557 s3 = src_althost;
558 }
559 /* if host mangling mode not enabled and no other spoof,
560 * also check the mangled form of their host */
561 else if (!IsDynSpoof(who))
562 {
563 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
564 s3 = src_althost;
565 }
566 }
567 #ifdef RB_IPV6
568 if(who->localClient->ip.ss_family == AF_INET6 &&
569 ipv4_from_ipv6((const struct sockaddr_in6 *)&who->localClient->ip, &ip4))
570 {
571 rb_sprintf(src_ip4host, "%s!%s@", who->name, who->username);
572 s4 = src_ip4host + strlen(src_ip4host);
573 rb_inet_ntop_sock((struct sockaddr *)&ip4,
574 s4, src_ip4host + sizeof src_ip4host - s4);
575 s4 = src_ip4host;
576 }
577 #endif
578
579 RB_DLINK_FOREACH(ptr, list->head)
580 {
581 actualBan = ptr->data;
582 if(match(actualBan->banstr, s) ||
583 match(actualBan->banstr, s2) ||
584 match_cidr(actualBan->banstr, s2) ||
585 match_extban(actualBan->banstr, who, chptr, CHFL_BAN) ||
586 (s3 != NULL && match(actualBan->banstr, s3))
587 #ifdef RB_IPV6
588 ||
589 (s4 != NULL && (match(actualBan->banstr, s4) || match_cidr(actualBan->banstr, s4)))
590 #endif
591 )
592 break;
593 else
594 actualBan = NULL;
595 }
596
597 if((actualBan != NULL) && ConfigChannel.use_except)
598 {
599 RB_DLINK_FOREACH(ptr, chptr->exceptlist.head)
600 {
601 actualExcept = ptr->data;
602
603 /* theyre exempted.. */
604 if(match(actualExcept->banstr, s) ||
605 match(actualExcept->banstr, s2) ||
606 match_cidr(actualExcept->banstr, s2) ||
607 match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
608 (s3 != NULL && match(actualExcept->banstr, s3)))
609 {
610 /* cache the fact theyre not banned */
611 if(msptr != NULL)
612 {
613 msptr->bants = chptr->bants;
614 msptr->flags &= ~CHFL_BANNED;
615 }
616
617 return CHFL_EXCEPTION;
618 }
619 }
620 }
621
622 /* cache the banned/not banned status */
623 if(msptr != NULL)
624 {
625 msptr->bants = chptr->bants;
626
627 if(actualBan != NULL)
628 {
629 msptr->flags |= CHFL_BANNED;
630 return CHFL_BAN;
631 }
632 else
633 {
634 msptr->flags &= ~CHFL_BANNED;
635 return 0;
636 }
637 }
638
639 if (actualBan && actualBan->forward && forward)
640 *forward = actualBan->forward;
641
642 return ((actualBan ? CHFL_BAN : 0));
643 }
644
645 /* is_banned()
646 *
647 * input - channel to check bans for, user to check bans against
648 * optional prebuilt buffers, optional forward channel pointer
649 * output - 1 if banned, else 0
650 * side effects -
651 */
652 int
653 is_banned(struct Channel *chptr, struct Client *who, struct membership *msptr,
654 const char *s, const char *s2, const char **forward)
655 {
656 return is_banned_list(chptr, &chptr->banlist, who, msptr, s, s2,
657 forward);
658 }
659
660 /* is_quieted()
661 *
662 * input - channel to check bans for, user to check bans against
663 * optional prebuilt buffers
664 * output - 1 if banned, else 0
665 * side effects -
666 */
667 int
668 is_quieted(struct Channel *chptr, struct Client *who, struct membership *msptr,
669 const char *s, const char *s2)
670 {
671 return is_banned_list(chptr, &chptr->quietlist, who, msptr, s, s2,
672 NULL);
673 }
674
675 /* can_join()
676 *
677 * input - client to check, channel to check for, key
678 * output - reason for not being able to join, else 0, channel name to forward to
679 * side effects -
680 * caveats - this function should only be called on a local user.
681 */
682 int
683 can_join(struct Client *source_p, struct Channel *chptr, const char *key, const char **forward)
684 {
685 rb_dlink_node *invite = NULL;
686 rb_dlink_node *ptr;
687 struct Ban *invex = NULL;
688 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
689 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
690 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
691 int use_althost = 0;
692 int i = 0;
693 hook_data_channel moduledata;
694
695 s_assert(source_p->localClient != NULL);
696
697 moduledata.client = source_p;
698 moduledata.chptr = chptr;
699 moduledata.approved = 0;
700
701 rb_sprintf(src_host, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
702 rb_sprintf(src_iphost, "%s!%s@%s", source_p->name, source_p->username, source_p->sockhost);
703 if(source_p->localClient->mangledhost != NULL)
704 {
705 /* if host mangling mode enabled, also check their real host */
706 if(!strcmp(source_p->host, source_p->localClient->mangledhost))
707 {
708 rb_sprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->orighost);
709 use_althost = 1;
710 }
711 /* if host mangling mode not enabled and no other spoof,
712 * also check the mangled form of their host */
713 else if (!IsDynSpoof(source_p))
714 {
715 rb_sprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->localClient->mangledhost);
716 use_althost = 1;
717 }
718 }
719
720 if((is_banned(chptr, source_p, NULL, src_host, src_iphost, forward)) == CHFL_BAN)
721 {
722 moduledata.approved = ERR_BANNEDFROMCHAN;
723 goto finish_join_check;
724 }
725
726 if(*chptr->mode.key && (EmptyString(key) || irccmp(chptr->mode.key, key)))
727 {
728 moduledata.approved = ERR_BADCHANNELKEY;
729 goto finish_join_check;
730 }
731
732 /* All checks from this point on will forward... */
733 if(forward)
734 *forward = chptr->mode.forward;
735
736 if(chptr->mode.mode & MODE_INVITEONLY)
737 {
738 RB_DLINK_FOREACH(invite, source_p->user->invited.head)
739 {
740 if(invite->data == chptr)
741 break;
742 }
743 if(invite == NULL)
744 {
745 if(!ConfigChannel.use_invex)
746 moduledata.approved = ERR_INVITEONLYCHAN;
747 RB_DLINK_FOREACH(ptr, chptr->invexlist.head)
748 {
749 invex = ptr->data;
750 if(match(invex->banstr, src_host)
751 || match(invex->banstr, src_iphost)
752 || match_cidr(invex->banstr, src_iphost)
753 || match_extban(invex->banstr, source_p, chptr, CHFL_INVEX)
754 || (use_althost && match(invex->banstr, src_althost)))
755 break;
756 }
757 if(ptr == NULL)
758 moduledata.approved = ERR_INVITEONLYCHAN;
759 }
760 }
761
762 if(chptr->mode.limit &&
763 rb_dlink_list_length(&chptr->members) >= (unsigned long) chptr->mode.limit)
764 i = ERR_CHANNELISFULL;
765 if(chptr->mode.mode & MODE_REGONLY && EmptyString(source_p->user->suser))
766 i = ERR_NEEDREGGEDNICK;
767 /* join throttling stuff --nenolod */
768 else if(chptr->mode.join_num > 0 && chptr->mode.join_time > 0)
769 {
770 if ((rb_current_time() - chptr->join_delta <=
771 chptr->mode.join_time) && (chptr->join_count >=
772 chptr->mode.join_num))
773 i = ERR_THROTTLE;
774 }
775
776 /* allow /invite to override +l/+r/+j also -- jilles */
777 if (i != 0 && invite == NULL)
778 {
779 RB_DLINK_FOREACH(invite, source_p->user->invited.head)
780 {
781 if(invite->data == chptr)
782 break;
783 }
784 if (invite == NULL)
785 moduledata.approved = i;
786 }
787
788 finish_join_check:
789 call_hook(h_can_join, &moduledata);
790
791 return moduledata.approved;
792 }
793
794 /* can_send()
795 *
796 * input - user to check in channel, membership pointer
797 * output - whether can explicitly send or not, else CAN_SEND_NONOP
798 * side effects -
799 */
800 int
801 can_send(struct Channel *chptr, struct Client *source_p, struct membership *msptr)
802 {
803 hook_data_channel_approval moduledata;
804
805 moduledata.approved = CAN_SEND_NONOP;
806
807 if(IsServer(source_p) || IsService(source_p))
808 return CAN_SEND_OPV;
809
810 if(MyClient(source_p) && hash_find_resv(chptr->chname) &&
811 !IsOper(source_p) && !IsExemptResv(source_p))
812 moduledata.approved = CAN_SEND_NO;
813
814 if(msptr == NULL)
815 {
816 msptr = find_channel_membership(chptr, source_p);
817
818 if(msptr == NULL)
819 {
820 /* if its +m or +n and theyre not in the channel,
821 * they cant send. we dont check bans here because
822 * theres no possibility of caching them --fl
823 */
824 if(chptr->mode.mode & MODE_NOPRIVMSGS || chptr->mode.mode & MODE_MODERATED)
825 moduledata.approved = CAN_SEND_NO;
826 else
827 moduledata.approved = CAN_SEND_NONOP;
828
829 return moduledata.approved;
830 }
831 }
832
833 if(chptr->mode.mode & MODE_MODERATED)
834 moduledata.approved = CAN_SEND_NO;
835
836 if(MyClient(source_p))
837 {
838 /* cached can_send */
839 if(msptr->bants == chptr->bants)
840 {
841 if(can_send_banned(msptr))
842 moduledata.approved = CAN_SEND_NO;
843 }
844 else if(is_banned(chptr, source_p, msptr, NULL, NULL, NULL) == CHFL_BAN
845 || is_quieted(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN)
846 moduledata.approved = CAN_SEND_NO;
847 }
848
849 if(is_chanop_voiced(msptr))
850 moduledata.approved = CAN_SEND_OPV;
851
852 moduledata.client = source_p;
853 moduledata.chptr = msptr->chptr;
854 moduledata.msptr = msptr;
855 moduledata.target = NULL;
856
857 call_hook(h_can_send, &moduledata);
858
859 return moduledata.approved;
860 }
861
862 /*
863 * flood_attack_channel
864 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
865 * says NOTICE must not auto reply
866 * - pointer to source Client
867 * - pointer to target channel
868 * output - 1 if target is under flood attack
869 * side effects - check for flood attack on target chptr
870 */
871 int
872 flood_attack_channel(int p_or_n, struct Client *source_p, struct Channel *chptr, char *chname)
873 {
874 int delta;
875
876 if(GlobalSetOptions.floodcount && MyClient(source_p))
877 {
878 if((chptr->first_received_message_time + 1) < rb_current_time())
879 {
880 delta = rb_current_time() - chptr->first_received_message_time;
881 chptr->received_number_of_privmsgs -= delta;
882 chptr->first_received_message_time = rb_current_time();
883 if(chptr->received_number_of_privmsgs <= 0)
884 {
885 chptr->received_number_of_privmsgs = 0;
886 chptr->flood_noticed = 0;
887 }
888 }
889
890 if((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
891 || chptr->flood_noticed)
892 {
893 if(chptr->flood_noticed == 0)
894 {
895 sendto_realops_snomask(SNO_BOTS, *chptr->chname == '&' ? L_ALL : L_NETWIDE,
896 "Possible Flooder %s[%s@%s] on %s target: %s",
897 source_p->name, source_p->username,
898 source_p->orighost,
899 source_p->servptr->name, chptr->chname);
900 chptr->flood_noticed = 1;
901
902 /* Add a bit of penalty */
903 chptr->received_number_of_privmsgs += 2;
904 }
905 if(MyClient(source_p) && (p_or_n != 1))
906 sendto_one(source_p,
907 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
908 me.name, source_p->name, chptr->chname);
909 return 1;
910 }
911 else
912 chptr->received_number_of_privmsgs++;
913 }
914
915 return 0;
916 }
917
918 /* find_bannickchange_channel()
919 * Input: client to check
920 * Output: channel preventing nick change
921 */
922 struct Channel *
923 find_bannickchange_channel(struct Client *client_p)
924 {
925 struct Channel *chptr;
926 struct membership *msptr;
927 rb_dlink_node *ptr;
928 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
929 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
930
931 if (!MyClient(client_p))
932 return NULL;
933
934 rb_sprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host);
935 rb_sprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost);
936
937 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
938 {
939 msptr = ptr->data;
940 chptr = msptr->chptr;
941 if (is_chanop_voiced(msptr))
942 continue;
943 /* cached can_send */
944 if (msptr->bants == chptr->bants)
945 {
946 if (can_send_banned(msptr))
947 return chptr;
948 }
949 else if (is_banned(chptr, client_p, msptr, src_host, src_iphost, NULL) == CHFL_BAN
950 || is_quieted(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN)
951 return chptr;
952 }
953 return NULL;
954 }
955
956 /* void check_spambot_warning(struct Client *source_p)
957 * Input: Client to check, channel name or NULL if this is a part.
958 * Output: none
959 * Side-effects: Updates the client's oper_warn_count_down, warns the
960 * IRC operators if necessary, and updates join_leave_countdown as
961 * needed.
962 */
963 void
964 check_spambot_warning(struct Client *source_p, const char *name)
965 {
966 int t_delta;
967 int decrement_count;
968 if((GlobalSetOptions.spam_num &&
969 (source_p->localClient->join_leave_count >= GlobalSetOptions.spam_num)))
970 {
971 if(source_p->localClient->oper_warn_count_down > 0)
972 source_p->localClient->oper_warn_count_down--;
973 else
974 source_p->localClient->oper_warn_count_down = 0;
975 if(source_p->localClient->oper_warn_count_down == 0 &&
976 name != NULL)
977 {
978 /* Its already known as a possible spambot */
979 sendto_realops_snomask(SNO_BOTS, L_NETWIDE,
980 "User %s (%s@%s) trying to join %s is a possible spambot",
981 source_p->name,
982 source_p->username, source_p->orighost, name);
983 source_p->localClient->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
984 }
985 }
986 else
987 {
988 if((t_delta =
989 (rb_current_time() - source_p->localClient->last_leave_time)) >
990 JOIN_LEAVE_COUNT_EXPIRE_TIME)
991 {
992 decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME);
993 if(name != NULL)
994 ;
995 else if(decrement_count > source_p->localClient->join_leave_count)
996 source_p->localClient->join_leave_count = 0;
997 else
998 source_p->localClient->join_leave_count -= decrement_count;
999 }
1000 else
1001 {
1002 if((rb_current_time() -
1003 (source_p->localClient->last_join_time)) < GlobalSetOptions.spam_time)
1004 {
1005 /* oh, its a possible spambot */
1006 source_p->localClient->join_leave_count++;
1007 }
1008 }
1009 if(name != NULL)
1010 source_p->localClient->last_join_time = rb_current_time();
1011 else
1012 source_p->localClient->last_leave_time = rb_current_time();
1013 }
1014 }
1015
1016 /* check_splitmode()
1017 *
1018 * input -
1019 * output -
1020 * side effects - compares usercount and servercount against their split
1021 * values and adjusts splitmode accordingly
1022 */
1023 void
1024 check_splitmode(void *unused)
1025 {
1026 if(splitchecking && (ConfigChannel.no_join_on_split || ConfigChannel.no_create_on_split))
1027 {
1028 /* not split, we're being asked to check now because someone
1029 * has left
1030 */
1031 if(!splitmode)
1032 {
1033 if(eob_count < split_servers || Count.total < split_users)
1034 {
1035 splitmode = 1;
1036 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1037 "Network split, activating splitmode");
1038 check_splitmode_ev = rb_event_addish("check_splitmode", check_splitmode, NULL, 2);
1039 }
1040 }
1041 /* in splitmode, check whether its finished */
1042 else if(eob_count >= split_servers && Count.total >= split_users)
1043 {
1044 splitmode = 0;
1045
1046 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1047 "Network rejoined, deactivating splitmode");
1048
1049 rb_event_delete(check_splitmode_ev);
1050 check_splitmode_ev = NULL;
1051 }
1052 }
1053 }
1054
1055
1056 /* allocate_topic()
1057 *
1058 * input - channel to allocate topic for
1059 * output - 1 on success, else 0
1060 * side effects - channel gets a topic allocated
1061 */
1062 static void
1063 allocate_topic(struct Channel *chptr)
1064 {
1065 void *ptr;
1066
1067 if(chptr == NULL)
1068 return;
1069
1070 ptr = rb_bh_alloc(topic_heap);
1071
1072 /* Basically we allocate one large block for the topic and
1073 * the topic info. We then split it up into two and shove it
1074 * in the chptr
1075 */
1076 chptr->topic = ptr;
1077 chptr->topic_info = (char *) ptr + TOPICLEN + 1;
1078 *chptr->topic = '\0';
1079 *chptr->topic_info = '\0';
1080 }
1081
1082 /* free_topic()
1083 *
1084 * input - channel which has topic to free
1085 * output -
1086 * side effects - channels topic is free'd
1087 */
1088 static void
1089 free_topic(struct Channel *chptr)
1090 {
1091 void *ptr;
1092
1093 if(chptr == NULL || chptr->topic == NULL)
1094 return;
1095
1096 /* This is safe for now - If you change allocate_topic you
1097 * MUST change this as well
1098 */
1099 ptr = chptr->topic;
1100 rb_bh_free(topic_heap, ptr);
1101 chptr->topic = NULL;
1102 chptr->topic_info = NULL;
1103 }
1104
1105 /* set_channel_topic()
1106 *
1107 * input - channel, topic to set, topic info and topic ts
1108 * output -
1109 * side effects - channels topic, topic info and TS are set.
1110 */
1111 void
1112 set_channel_topic(struct Channel *chptr, const char *topic, const char *topic_info, time_t topicts)
1113 {
1114 if(strlen(topic) > 0)
1115 {
1116 if(chptr->topic == NULL)
1117 allocate_topic(chptr);
1118 rb_strlcpy(chptr->topic, topic, TOPICLEN + 1);
1119 rb_strlcpy(chptr->topic_info, topic_info, USERHOST_REPLYLEN);
1120 chptr->topic_time = topicts;
1121 }
1122 else
1123 {
1124 if(chptr->topic != NULL)
1125 free_topic(chptr);
1126 chptr->topic_time = 0;
1127 }
1128 }
1129
1130 /* channel_modes()
1131 *
1132 * inputs - pointer to channel
1133 * - pointer to client
1134 * output - string with simple modes
1135 * side effects - result from previous calls overwritten
1136 *
1137 * Stolen from ShadowIRCd 4 --nenolod
1138 */
1139 const char *
1140 channel_modes(struct Channel *chptr, struct Client *client_p)
1141 {
1142 int i;
1143 char buf1[BUFSIZE];
1144 char buf2[BUFSIZE];
1145 static char final[BUFSIZE];
1146 char *mbuf = buf1;
1147 char *pbuf = buf2;
1148
1149 *mbuf++ = '+';
1150 *pbuf = '\0';
1151
1152 for (i = 0; i < 256; i++)
1153 if(chptr->mode.mode & chmode_flags[i])
1154 *mbuf++ = i;
1155
1156 if(chptr->mode.limit)
1157 {
1158 *mbuf++ = 'l';
1159
1160 if(!IsClient(client_p) || IsMember(client_p, chptr))
1161 pbuf += rb_sprintf(pbuf, " %d", chptr->mode.limit);
1162 }
1163
1164 if(*chptr->mode.key)
1165 {
1166 *mbuf++ = 'k';
1167
1168 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1169 pbuf += rb_sprintf(pbuf, " %s", chptr->mode.key);
1170 }
1171
1172 if(chptr->mode.join_num)
1173 {
1174 *mbuf++ = 'j';
1175
1176 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1177 pbuf += rb_sprintf(pbuf, " %d:%d", chptr->mode.join_num,
1178 chptr->mode.join_time);
1179 }
1180
1181 if(*chptr->mode.forward &&
1182 (ConfigChannel.use_forward || !IsClient(client_p)))
1183 {
1184 *mbuf++ = 'f';
1185
1186 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1187 pbuf += rb_sprintf(pbuf, " %s", chptr->mode.forward);
1188 }
1189
1190 *mbuf = '\0';
1191
1192 rb_strlcpy(final, buf1, sizeof final);
1193 rb_strlcat(final, buf2, sizeof final);
1194 return final;
1195 }
1196
1197 /* void send_cap_mode_changes(struct Client *client_p,
1198 * struct Client *source_p,
1199 * struct Channel *chptr, int cap, int nocap)
1200 * Input: The client sending(client_p), the source client(source_p),
1201 * the channel to send mode changes for(chptr)
1202 * Output: None.
1203 * Side-effects: Sends the appropriate mode changes to capable servers.
1204 *
1205 * Reverted back to my original design, except that we now keep a count
1206 * of the number of servers which each combination as an optimisation, so
1207 * the capabs combinations which are not needed are not worked out. -A1kmm
1208 *
1209 * Removed most code here because we don't need to be compatible with ircd
1210 * 2.8.21+CSr and stuff. --nenolod
1211 */
1212 void
1213 send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1214 struct Channel *chptr, struct ChModeChange mode_changes[], int mode_count)
1215 {
1216 static char modebuf[BUFSIZE];
1217 static char parabuf[BUFSIZE];
1218 int i, mbl, pbl, nc, mc, preflen, len;
1219 char *pbuf;
1220 const char *arg;
1221 int cap;
1222 int nocap;
1223 int dir;
1224 int arglen;
1225
1226 /* Now send to servers... */
1227 mc = 0;
1228 nc = 0;
1229 pbl = 0;
1230 parabuf[0] = 0;
1231 pbuf = parabuf;
1232 dir = MODE_QUERY;
1233
1234 mbl = preflen = rb_sprintf(modebuf, ":%s TMODE %ld %s ",
1235 use_id(source_p), (long) chptr->channelts,
1236 chptr->chname);
1237
1238 /* loop the list of - modes we have */
1239 for (i = 0; i < mode_count; i++)
1240 {
1241 /* if they dont support the cap we need, or they do support a cap they
1242 * cant have, then dont add it to the modebuf.. that way they wont see
1243 * the mode
1244 */
1245 if (mode_changes[i].letter == 0)
1246 continue;
1247
1248 cap = mode_changes[i].caps;
1249 nocap = mode_changes[i].nocaps;
1250
1251 if (!EmptyString(mode_changes[i].id))
1252 arg = mode_changes[i].id;
1253 else
1254 arg = mode_changes[i].arg;
1255
1256 if(arg)
1257 {
1258 arglen = strlen(arg);
1259
1260 /* dont even think about it! --fl */
1261 if(arglen > MODEBUFLEN - 5)
1262 continue;
1263 }
1264
1265 /* if we're creeping past the buf size, we need to send it and make
1266 * another line for the other modes
1267 * XXX - this could give away server topology with uids being
1268 * different lengths, but not much we can do, except possibly break
1269 * them as if they were the longest of the nick or uid at all times,
1270 * which even then won't work as we don't always know the uid -A1kmm.
1271 */
1272 if(arg && ((mc == MAXMODEPARAMSSERV) ||
1273 ((mbl + pbl + arglen + 4) > (BUFSIZE - 3))))
1274 {
1275 if(nc != 0)
1276 sendto_server(client_p, chptr, cap, nocap,
1277 "%s %s", modebuf, parabuf);
1278 nc = 0;
1279 mc = 0;
1280
1281 mbl = preflen;
1282 pbl = 0;
1283 pbuf = parabuf;
1284 parabuf[0] = 0;
1285 dir = MODE_QUERY;
1286 }
1287
1288 if(dir != mode_changes[i].dir)
1289 {
1290 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1291 dir = mode_changes[i].dir;
1292 }
1293
1294 modebuf[mbl++] = mode_changes[i].letter;
1295 modebuf[mbl] = 0;
1296 nc++;
1297
1298 if(arg != NULL)
1299 {
1300 len = rb_sprintf(pbuf, "%s ", arg);
1301 pbuf += len;
1302 pbl += len;
1303 mc++;
1304 }
1305 }
1306
1307 if(pbl && parabuf[pbl - 1] == ' ')
1308 parabuf[pbl - 1] = 0;
1309
1310 if(nc != 0)
1311 sendto_server(client_p, chptr, cap, nocap, "%s %s", modebuf, parabuf);
1312 }
1313
1314 void
1315 resv_chan_forcepart(const char *name, const char *reason, int temp_time)
1316 {
1317 rb_dlink_node *ptr;
1318 rb_dlink_node *next_ptr;
1319 struct Channel *chptr;
1320 struct membership *msptr;
1321 struct Client *target_p;
1322
1323 if(!ConfigChannel.resv_forcepart)
1324 return;
1325
1326 /* for each user on our server in the channel list
1327 * send them a PART, and notify opers.
1328 */
1329 chptr = find_channel(name);
1330 if(chptr != NULL)
1331 {
1332 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head)
1333 {
1334 msptr = ptr->data;
1335 target_p = msptr->client_p;
1336
1337 if(IsExemptResv(target_p))
1338 continue;
1339
1340 sendto_server(target_p, chptr, CAP_TS6, NOCAPS,
1341 ":%s PART %s", target_p->id, chptr->chname);
1342
1343 sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :%s",
1344 target_p->name, target_p->username,
1345 target_p->host, chptr->chname, target_p->name);
1346
1347 remove_user_from_channel(msptr);
1348
1349 /* notify opers & user they were removed from the channel */
1350 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1351 "Forced PART for %s!%s@%s from %s (%s)",
1352 target_p->name, target_p->username,
1353 target_p->host, name, reason);
1354
1355 if(temp_time > 0)
1356 sendto_one_notice(target_p, ":*** Channel %s is temporarily unavailable on this server.",
1357 name);
1358 else
1359 sendto_one_notice(target_p, ":*** Channel %s is no longer available on this server.",
1360 name);
1361 }
1362 }
1363 }