1 /* Unreal Internet Relay Chat Daemon, src/channel.c
2  *   Copyright (C) 1990 Jarkko Oikarinen and
3  *                      University of Oulu, Co Center
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 1, or (at your option)
8  *   any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /*
20  * 23 Jun 1999
21  * Changing unsigned int modes to long
22  * --- Sts - 28 May 1999
23     Incorporated twilight mode system
24 */
25 /* -- Jto -- 09 Jul 1990
26  * Bug fix
27  */
28 
29 /* -- Jto -- 03 Jun 1990
30  * Moved m_channel() and related functions from s_msg.c to here
31  * Many changes to start changing into string channels...
32  */
33 
34 /* -- Jto -- 24 May 1990
35  * Moved is_full() from list.c
36  */
37 
38 
39 #include "struct.h"
40 #include "common.h"
41 #include "sys.h"
42 #include "numeric.h"
43 #include "channel.h"
44 #include "msg.h"		/* For TOK_*** and MSG_*** strings  */
45 #include "hash.h"		/* For CHANNELHASHSIZE */
46 #include "h.h"
47 #include "proto.h"
48 #include <string.h>
49 
50 ID_Copyright
51     ("(C) 1990 University of Oulu, Computing Center and Jarkko Oikarinen");
52 
53 long opermode = 0;
54 aChannel *channel = NullChn;
55 extern char backupbuf[];
56 extern ircstats IRCstats;
57 
58 #ifndef NO_FDLIST
59 extern int lifesux;
60 #endif
61 
62 /* Some forward declarations */
63 void add_invite(aClient *, aChannel *);
64 char *clean_ban_mask(char *, int, aClient *);
65 void channel_modes(aClient *, char *, char *, aChannel *);
66 int check_channelmask(aClient *, aClient *, char *);
67 
68 void sub1_from_channel(aChannel *);
69 
70 void clean_channelname(char *);
71 void del_invite(aClient *, aChannel *);
72 
73 #ifdef NEWCHFLOODPROT
74 void chanfloodtimer_del(aChannel *chptr, char mflag, long mbit);
75 void chanfloodtimer_stopchantimers(aChannel *chptr);
76 #endif
77 
78 /*
79  * some buffers for rebuilding channel/nick lists with ,'s
80  */
81 static char nickbuf[BUFSIZE], buf[BUFSIZE];
82 MODVAR char modebuf[BUFSIZE], parabuf[BUFSIZE];
83 #include "sjoin.h"
84 
85 #define MODESYS_LINKOK		/* We do this for a TEST  */
86 aCtab cFlagTab[] = {
87 	{MODE_LIMIT, 'l', 0, 1},
88 	{MODE_VOICE, 'v', 1, 1},
89 	{MODE_HALFOP, 'h', 0, 1},
90 	{MODE_CHANOP, 'o', 0, 1},
91 	{MODE_PRIVATE, 'p', 0, 0},
92 	{MODE_SECRET, 's', 0, 0},
93 	{MODE_MODERATED, 'm', 1, 0},
94 	{MODE_NOPRIVMSGS, 'n', 1, 0},
95 	{MODE_TOPICLIMIT, 't', 1, 0},
96 	{MODE_INVITEONLY, 'i', 1, 0},
97 	{MODE_KEY, 'k', 1, 1},
98 	{MODE_RGSTR, 'r', 0, 0},
99 	{MODE_RGSTRONLY, 'R', 0, 0},
100 	{MODE_NOCOLOR, 'c', 0, 0},
101 	{MODE_CHANPROT, 'a', 0, 1},
102 	{MODE_CHANOWNER, 'q', 0, 1},
103 	{MODE_OPERONLY, 'O', 0, 0},
104 	{MODE_ADMONLY, 'A', 0, 0},
105 	{MODE_LINK, 'L', 0, 1},
106 	{MODE_NOKICKS, 'Q', 0, 0},
107 	{MODE_BAN, 'b', 1, 1},
108 	{MODE_STRIP, 'S', 0, 0},	/* works? */
109 	{MODE_EXCEPT, 'e', 1, 0},	/* exception ban */
110 	{MODE_INVEX, 'I', 1, 0},	/* exception ban */
111 	{MODE_NOKNOCK, 'K', 0, 0},	/* knock knock (no way!) */
112 	{MODE_NOINVITE, 'V', 0, 0},	/* no invites */
113 	{MODE_FLOODLIMIT, 'f', 0, 1},	/* flood limiter */
114 	{MODE_MODREG, 'M', 0, 0},	/* Need umode +r to talk */
115 	{MODE_NOCTCP, 'C', 0, 0},	/* no CTCPs */
116 	{MODE_AUDITORIUM, 'u', 0, 0},
117 	{MODE_ONLYSECURE, 'z', 0, 0},
118 	{MODE_NONICKCHANGE, 'N', 0, 0},
119 	{0x0, 0x0, 0x0}
120 };
121 
122 
123 #define	BADOP_BOUNCE	1
124 #define	BADOP_USER	2
125 #define	BADOP_SERVER	3
126 #define	BADOP_OVERRIDE	4
127 
128 char cmodestring[512];
129 
op_can_override(aClient * sptr)130 inline int op_can_override(aClient *sptr)
131 {
132 #ifndef NO_OPEROVERRIDE
133 	if (!IsOper(sptr))
134 		return 0;
135 	if (MyClient(sptr) && !OPCanOverride(sptr))
136 		return 0;
137 	return 1;
138 #else
139 	return 0;
140 #endif
141 }
142 
make_cmodestr(void)143 void make_cmodestr(void)
144 {
145 	char *p = &cmodestring[0];
146 	aCtab *tab = &cFlagTab[0];
147 #ifdef EXTCMODE
148 	int i;
149 #endif
150 	while (tab->mode != 0x0)
151 	{
152 		*p = tab->flag;
153 		p++;
154 		tab++;
155 	}
156 #ifdef EXTCMODE
157 	for (i=0; i <= Channelmode_highest; i++)
158 		if (Channelmode_Table[i].flag)
159 			*p++ = Channelmode_Table[i].flag;
160 #endif
161 	*p = '\0';
162 }
163 
Halfop_mode(long mode)164 int  Halfop_mode(long mode)
165 {
166 	aCtab *tab = &cFlagTab[0];
167 
168 	while (tab->mode != 0x0)
169 	{
170 		if (tab->mode == mode)
171 			return (tab->halfop == 1 ? TRUE : FALSE);
172 		tab++;
173 	}
174 	return TRUE;
175 }
176 
177 
178 /*
179  * return the length (>=0) of a chain of links.
180  */
list_length(Link * lp)181 static int list_length(Link *lp)
182 {
183 	int  count = 0;
184 
185 	for (; lp; lp = lp->next)
186 		count++;
187 	return count;
188 }
189 
find_member_link(Member * lp,aClient * ptr)190 Member	*find_member_link(Member *lp, aClient *ptr)
191 {
192 	if (ptr)
193 		while (lp)
194 		{
195 			if (lp->cptr == ptr)
196 				return (lp);
197 			lp = lp->next;
198 		}
199 	return NULL;
200 }
201 
find_membership_link(Membership * lp,aChannel * ptr)202 Membership *find_membership_link(Membership *lp, aChannel *ptr)
203 {
204 	if (ptr)
205 		while (lp)
206 		{
207 			if (lp->chptr == ptr)
208 				return (lp);
209 			lp = lp->next;
210 		}
211 	return NULL;
212 }
213 /*
214  * Member functions
215 */
make_member(void)216 Member	*make_member(void)
217 {
218 	Member *lp;
219 	unsigned int	i;
220 
221 	if (freemember == NULL)
222 	{
223 		for (i = 1; i <= (4072/sizeof(Member)); ++i)
224 		{
225 			lp = (Member *)MyMalloc(sizeof(Member));
226 			lp->cptr = NULL;
227 			lp->flags = 0;
228 			lp->next = freemember;
229 			freemember = lp;
230 		}
231 	}
232 	lp = freemember;
233 	freemember = freemember->next;
234 	lp->next = NULL;
235 	return lp;
236 }
237 
free_member(Member * lp)238 void	free_member(Member *lp)
239 {
240 	if (lp)
241 	{
242 		lp->next = freemember;
243 		lp->cptr = NULL;
244 		lp->flags = 0;
245 		freemember = lp;
246 	}
247 }
248 
249 /*
250  * Membership functions
251 */
make_membership(int local)252 Membership	*make_membership(int local)
253 {
254 	Membership *lp = NULL;
255 	MembershipL *lp2 = NULL;
256 	unsigned int	i;
257 
258 	if (!local)
259 	{
260 		if (freemembership == NULL)
261 		{
262 			for (i = 1; i <= (4072/sizeof(Membership)); i++)
263 			{
264 				lp = (Membership *)MyMalloc(sizeof(Membership));
265 				lp->next = freemembership;
266 				freemembership = lp;
267 			}
268 			lp = freemembership;
269 			freemembership = lp->next;
270 		}
271 		else
272 		{
273 			lp = freemembership;
274 			freemembership = freemembership->next;
275 		}
276 		bzero(lp, sizeof(Membership));
277 	}
278 	else
279 	{
280 		if (freemembershipL == NULL)
281 		{
282 			for (i = 1; i <= (4072/sizeof(MembershipL)); i++)
283 			{
284 				lp2 = (MembershipL *)MyMalloc(sizeof(MembershipL));
285 				lp2->next = (Membership *) freemembershipL;
286 				freemembershipL = lp2;
287 			}
288 			lp2 = freemembershipL;
289 			freemembershipL = (MembershipL *) lp2->next;
290 			Debug((DEBUG_ERROR, "floodmode::alloc gotone"));
291 		}
292 		else
293 		{
294 			lp2 = freemembershipL;
295 			freemembershipL = (MembershipL *) freemembershipL->next;
296 			Debug((DEBUG_ERROR, "floodmode::freelist gotone"));
297 		}
298 		Debug((DEBUG_ERROR, "floodmode:: bzeroing"));
299 		bzero(lp2, sizeof(MembershipL));
300 	}
301 	if (local)
302 	{
303 		return ((Membership *) lp2);
304 	}
305 	return lp;
306 }
307 
free_membership(Membership * lp,int local)308 void	free_membership(Membership *lp, int local)
309 {
310 	if (lp)
311 	{
312 		if (!local)
313 		{
314 			lp->next = freemembership;
315 			freemembership = lp;
316 		}
317 		else
318 		{
319 			lp->next = (Membership *) freemembershipL;
320 			freemembershipL = (MembershipL *) lp;
321 		}
322 	}
323 }
324 
325 /*
326 ** find_chasing
327 **	Find the client structure for a nick name (user) using history
328 **	mechanism if necessary. If the client is not found, an error
329 **	message (NO SUCH NICK) is generated. If the client was found
330 **	through the history, chasing will be 1 and otherwise 0.
331 */
find_chasing(aClient * sptr,char * user,int * chasing)332 aClient *find_chasing(aClient *sptr, char *user, int *chasing)
333 {
334 	aClient *who = find_client(user, (aClient *)NULL);
335 
336 	if (chasing)
337 		*chasing = 0;
338 	if (who)
339 	{
340 		if (!IsServer(who))
341 			return who;
342 		else
343 			return NULL;
344 	}
345 	if (!(who = get_history(user, (long)KILLCHASETIMELIMIT)))
346 	{
347 		sendto_one(sptr, err_str(ERR_NOSUCHNICK),
348 		    me.name, sptr->name, user);
349 		return NULL;
350 	}
351 	if (chasing)
352 		*chasing = 1;
353 	if (!IsServer(who))
354 		return who;
355 	else return NULL;
356 }
357 
358 /*
359  * add_listmode - Add a listmode (+beI) with the specified banid to
360  *                the specified channel.
361  */
362 
add_listmode(Ban ** list,aClient * cptr,aChannel * chptr,char * banid)363 int add_listmode(Ban **list, aClient *cptr, aChannel *chptr, char *banid)
364 {
365 	Ban *ban;
366 	int cnt = 0, len;
367 
368 	if (MyClient(cptr))
369 		(void)collapse(banid);
370 
371 	len = strlen(banid);
372 	if (!*list && ((len > MAXBANLENGTH) || (MAXBANS < 1)))
373 	{
374 		sendto_one(cptr, err_str(ERR_BANLISTFULL),
375 			me.name, cptr->name, chptr->chname, banid);
376 		return -1;
377 	}
378 	for (ban = *list; ban; ban = ban->next)
379 	{
380 		len += strlen(ban->banstr);
381 		if (MyClient(cptr))
382 			if ((len > MAXBANLENGTH) || (++cnt >= MAXBANS))
383 			{
384 				sendto_one(cptr, err_str(ERR_BANLISTFULL),
385 				    me.name, cptr->name, chptr->chname, banid);
386 				return -1;
387 			}
388 			else
389 			{
390 #ifdef SOCALLEDSMARTBANNING
391 			  /* Temp workaround added in b19. -- Syzop */
392 			  if (!mycmp(ban->banstr, banid) || (!strchr(banid, '\\') && !strchr(ban->banstr, '\\')))
393 				if (!match(ban->banstr, banid))
394 					return -1;
395 #endif
396 			  if (!mycmp(ban->banstr, banid))
397 			  	return -1;
398 			}
399 		else if (!mycmp(ban->banstr, banid))
400 			return -1;
401 
402 	}
403 	ban = make_ban();
404 	bzero((char *)ban, sizeof(Ban));
405 	ban->next = *list;
406 	ban->banstr = (char *)MyMalloc(strlen(banid) + 1);
407 	(void)strcpy(ban->banstr, banid);
408 	ban->who = (char *)MyMalloc(strlen(cptr->name) + 1);
409 	(void)strcpy(ban->who, cptr->name);
410 	ban->when = TStime();
411 	*list = ban;
412 	return 0;
413 }
414 /*
415  * del_listmode - delete a listmode (+beI) from a channel
416  *                that matches the specified banid.
417  */
del_listmode(Ban ** list,aChannel * chptr,char * banid)418 int del_listmode(Ban **list, aChannel *chptr, char *banid)
419 {
420 	Ban **ban;
421 	Ban *tmp;
422 
423 	if (!banid)
424 		return -1;
425 	for (ban = list; *ban; ban = &((*ban)->next))
426 	{
427 		if (mycmp(banid, (*ban)->banstr) == 0)
428 		{
429 			tmp = *ban;
430 			*ban = tmp->next;
431 			MyFree(tmp->banstr);
432 			MyFree(tmp->who);
433 			free_ban(tmp);
434 			return 0;
435 		}
436 	}
437 	return -1;
438 }
439 
440 /*
441  * IsMember - returns 1 if a person is joined
442  * Moved to struct.h
443  */
444 
445 /* Those pointers can be used by extended ban modules so they
446  * don't have to do 4 make_nick_user_host()'s all the time:
447  */
448 char *ban_realhost = NULL, *ban_virthost = NULL, *ban_cloakhost = NULL, *ban_ip = NULL;
449 
450 /** is_banned - Check if a user is banned on a channel.
451  * @param sptr   Client to check (can be remote client)
452  * @param chptr  Channel to check
453  * @param type   Type of ban to check for (BANCHK_*)
454  * @returns      A pointer to the ban struct if banned, otherwise NULL.
455  * @comments     Simple wrapper for is_banned_with_nick()
456  */
is_banned(aClient * sptr,aChannel * chptr,int type)457 inline Ban *is_banned(aClient *sptr, aChannel *chptr, int type)
458 {
459 	return is_banned_with_nick(sptr, chptr, type, sptr->name);
460 }
461 
462 /** ban_check_mask - Checks if the current user in ban checking (ban_ip, etc) matches the specified n!u@h mask -or- run an extended ban.
463  * @param sptr         Client to check (can be remote client)
464  * @param chptr        Channel to check
465  * @param banstr       Mask string to check user
466  * @param type         Type of ban to check for (BANCHK_*)
467  * @param no_extbans   0 to check extbans, nonzero to disable extban checking.
468  * @returns            Nonzero if the mask/extban succeeds. Zero if it doesn't.
469  * @comments           This is basically extracting the mask and extban check from is_banned_with_nick, but with being a bit more strict in what an extban is.
470  *                     Strange things could happen if this is called outside standard ban checking.
471  */
ban_check_mask(aClient * sptr,aChannel * chptr,char * banstr,int type,int no_extbans)472 inline int ban_check_mask(aClient *sptr, aChannel *chptr, char *banstr, int type, int no_extbans)
473 {
474 	Extban *extban = NULL;
475 	if (!no_extbans && banstr[0] == '~' && banstr[1] != '\0' && banstr[2] == ':')
476 	{
477 		/* Is an extended ban. */
478 		extban = findmod_by_bantype(banstr[1]);
479 		if (!extban)
480 		{
481 			return 0;
482 		}
483 		else
484 		{
485 			return extban->is_banned(sptr, chptr, banstr, type);
486 		}
487 	}
488 	else
489 	{
490 		/* Is a n!u@h mask. */
491 		return extban_is_banned_helper(banstr);
492 	}
493 }
494 
495 /** is_banned_with_nick - Check if a user is banned on a channel.
496  * @param sptr   Client to check (can be remote client)
497  * @param chptr  Channel to check
498  * @param type   Type of ban to check for (BANCHK_*)
499  * @param nick   Nick of the user
500  * @returns      A pointer to the ban struct if banned, otherwise NULL.
501  */
is_banned_with_nick(aClient * sptr,aChannel * chptr,int type,char * nick)502 Ban *is_banned_with_nick(aClient *sptr, aChannel *chptr, int type, char *nick)
503 {
504 	Ban *tmp, *tmp2;
505 	char *s;
506 	static char realhost[NICKLEN + USERLEN + HOSTLEN + 24];
507 	static char cloakhost[NICKLEN + USERLEN + HOSTLEN + 24];
508 	static char virthost[NICKLEN + USERLEN + HOSTLEN + 24];
509 	static char     nuip[NICKLEN + USERLEN + HOSTLEN + 24];
510 	Extban *extban;
511 
512 	if (!IsPerson(sptr) || !chptr->banlist)
513 		return NULL;
514 
515 	ban_realhost = realhost;
516 	ban_ip = ban_virthost = ban_cloakhost = NULL;
517 
518 	/* Might it be possible in the future to include the possiblity for SupportNICKIP(sptr->from), SupportCLK(sptr->from)? -- aquanight */
519 	/* Nope, because servers not directly connected to the server in question have no idea about the capabilities at all.
520 	 * However, there's no need for a MyConnect() requirement, just check if GetIP() is non-NULL and
521 	 * if sptr->user->cloakedhost contains anything... -- Syzop
522 	 */
523 	if (GetIP(sptr))
524 	{
525 		make_nick_user_host_r(nuip, nick, sptr->user->username, GetIP(sptr));
526 		ban_ip = nuip;
527 	}
528 
529 	if (*sptr->user->cloakedhost)
530 	{
531 		make_nick_user_host_r(cloakhost, nick, sptr->user->username, sptr->user->cloakedhost);
532 		ban_cloakhost = cloakhost;
533 	}
534 
535 	if (IsSetHost(sptr) && strcmp(sptr->user->realhost, sptr->user->virthost))
536 	{
537 		make_nick_user_host_r(virthost, nick, sptr->user->username, sptr->user->virthost);
538 		ban_virthost = virthost;
539 	}
540 
541 
542 	make_nick_user_host_r(realhost, nick, sptr->user->username, sptr->user->realhost);
543 
544 	/* We now check +b first, if a +b is found we then see if there is a +e.
545 	 * If a +e was found we return NULL, if not, we return the ban.
546 	 */
547 	for (tmp = chptr->banlist; tmp; tmp = tmp->next)
548 	{
549 		if (!ban_check_mask(sptr, chptr, tmp->banstr, type, 0))
550 			continue;
551 
552 		/* Ban found, now check for +e */
553 		for (tmp2 = chptr->exlist; tmp2; tmp2 = tmp2->next)
554 		{
555 			if (ban_check_mask(sptr, chptr, tmp2->banstr, type, 0))
556 				return NULL; /* except matched */
557 		}
558 		break; /* ban found and not on except */
559 	}
560 
561 	return (tmp);
562 }
563 
extban_is_banned_helper(char * buf)564 int extban_is_banned_helper(char *buf)
565 {
566 	if ((match(buf, ban_realhost) == 0) ||
567 	    (ban_virthost && (match(buf, ban_virthost) == 0)) ||
568 	    (ban_ip && (match(buf, ban_ip) == 0)) ||
569 	    (ban_cloakhost && (match(buf, ban_cloakhost) == 0)) )
570 		return 1;
571 
572 	return 0;
573 }
574 
575 /*
576  * Checks if the "user" IRC is banned, used by +mu.
577  */
is_irc_banned(aChannel * chptr)578 static int is_irc_banned(aChannel *chptr)
579 {
580 	Ban *tmp;
581 	/* Check for this user, ident/host are "illegal" on purpose */
582 	char *check = "IRC!\001@\001";
583 
584 	for (tmp = chptr->banlist; tmp; tmp = tmp->next)
585 		if (match(tmp->banstr, check) == 0)
586 		{
587 			/* Ban found, now check for +e */
588 			for (tmp = chptr->exlist; tmp; tmp = tmp->next)
589 				if (match(tmp->banstr, check) == 0)
590 					return 0; /* In exception list */
591 			return 1;
592 		}
593 	return 0;
594 }
595 
596 /*
597  * adds a user to a channel by adding another link to the channels member
598  * chain.
599  */
add_user_to_channel(aChannel * chptr,aClient * who,int flags)600 void add_user_to_channel(aChannel *chptr, aClient *who, int flags)
601 {
602 	Member *ptr;
603 	Membership *ptr2;
604 
605 	if (who->user)
606 	{
607 		ptr = make_member();
608 		ptr->cptr = who;
609 		ptr->flags = flags;
610 		ptr->next = chptr->members;
611 		chptr->members = ptr;
612 		chptr->users++;
613 
614 		ptr2 = make_membership(MyClient(who));
615 		/* we should make this more efficient --stskeeps
616 		   is now, as we only use it in membership */
617 		ptr2->chptr = chptr;
618 		ptr2->next = who->user->channel;
619 		ptr2->flags = flags;
620 		who->user->channel = ptr2;
621 		who->user->joined++;
622 	}
623 }
624 
remove_user_from_channel(aClient * sptr,aChannel * chptr)625 void remove_user_from_channel(aClient *sptr, aChannel *chptr)
626 {
627 	Member **curr; Membership **curr2;
628 	Member *tmp; Membership *tmp2;
629 	Member *lp = chptr->members;
630 
631 	/* find 1st entry in list that is not user */
632 	for (; lp && (lp->cptr == sptr); lp = lp->next);
633 	for (;;)
634 	{
635 		for (curr = &chptr->members; (tmp = *curr); curr = &tmp->next)
636 			if (tmp->cptr == sptr)
637 			{
638 				*curr = tmp->next;
639 				free_member(tmp);
640 				break;
641 			}
642 		for (curr2 = &sptr->user->channel; (tmp2 = *curr2); curr2 = &tmp2->next)
643 			if (tmp2->chptr == chptr)
644 			{
645 				*curr2 = tmp2->next;
646 				free_membership(tmp2, MyClient(sptr));
647 				break;
648 			}
649 		sptr->user->joined--;
650 		if (lp)
651 			break;
652 		if (chptr->members)
653 			sptr = chptr->members->cptr;
654 		else
655 			break;
656 		sub1_from_channel(chptr);
657 	}
658 	sub1_from_channel(chptr);
659 }
660 
get_access(aClient * cptr,aChannel * chptr)661 long get_access(aClient *cptr, aChannel *chptr)
662 {
663 	Membership *lp;
664 	if (chptr)
665 		if ((lp = find_membership_link(cptr->user->channel, chptr)))
666 			return lp->flags;
667 	return 0;
668 }
669 
is_chan_op(aClient * cptr,aChannel * chptr)670 int  is_chan_op(aClient *cptr, aChannel *chptr)
671 {
672 	Membership *lp;
673 /* chanop/halfop ? */
674 	if (IsServer(cptr))
675 		return 1;
676 	if (chptr)
677 		if ((lp = find_membership_link(cptr->user->channel, chptr)))
678 #ifdef PREFIX_AQ
679 			return ((lp->flags & (CHFL_CHANOP|CHFL_CHANPROT|CHFL_CHANOWNER)));
680 #else
681 			return ((lp->flags & CHFL_CHANOP));
682 #endif
683 
684 	return 0;
685 }
686 
has_voice(aClient * cptr,aChannel * chptr)687 int  has_voice(aClient *cptr, aChannel *chptr)
688 {
689 	Membership *lp;
690 
691 	if (IsServer(cptr))
692 		return 1;
693 	if (chptr)
694 		if ((lp = find_membership_link(cptr->user->channel, chptr)))
695 			return (lp->flags & CHFL_VOICE);
696 
697 	return 0;
698 }
is_halfop(aClient * cptr,aChannel * chptr)699 int  is_halfop(aClient *cptr, aChannel *chptr)
700 {
701 	Membership *lp;
702 
703 	if (IsServer(cptr))
704 		return 1;
705 	if (chptr)
706 		if ((lp = find_membership_link(cptr->user->channel, chptr)))
707 			if (!(lp->flags & CHFL_CHANOP))
708 				return (lp->flags & CHFL_HALFOP);
709 
710 	return 0;
711 }
712 
is_chanowner(aClient * cptr,aChannel * chptr)713 int  is_chanowner(aClient *cptr, aChannel *chptr)
714 {
715 	Membership *lp;
716 
717 	if (IsServer(cptr))
718 		return 1;
719 	if (chptr)
720 		if ((lp = find_membership_link(cptr->user->channel, chptr)))
721 			return (lp->flags & CHFL_CHANOWNER);
722 
723 	return 0;
724 }
725 
is_chanownprotop(aClient * cptr,aChannel * chptr)726 int is_chanownprotop(aClient *cptr, aChannel *chptr) {
727 	Membership *lp;
728 
729 	if (IsServer(cptr))
730 		return 1;
731 	if (chptr)
732 		if ((lp = find_membership_link(cptr->user->channel, chptr)))
733 			if (lp->flags & (CHFL_CHANOWNER|CHFL_CHANPROT|CHFL_CHANOP))
734 				return 1;
735 	return 0;
736 }
737 
is_skochanop(aClient * cptr,aChannel * chptr)738 int is_skochanop(aClient *cptr, aChannel *chptr) {
739 	Membership *lp;
740 
741 	if (IsServer(cptr))
742 		return 1;
743 	if (chptr)
744 		if ((lp = find_membership_link(cptr->user->channel, chptr)))
745 #ifdef PREFIX_AQ
746 			if (lp->flags & (CHFL_CHANOWNER|CHFL_CHANPROT|CHFL_CHANOP|CHFL_HALFOP))
747 #else
748 			if (lp->flags & (CHFL_CHANOP|CHFL_HALFOP))
749 #endif
750 				return 1;
751 	return 0;
752 }
753 
is_chanprot(aClient * cptr,aChannel * chptr)754 int  is_chanprot(aClient *cptr, aChannel *chptr)
755 {
756 	Membership *lp;
757 
758 	if (chptr)
759 		if ((lp = find_membership_link(cptr->user->channel, chptr)))
760 			return (lp->flags & CHFL_CHANPROT);
761 
762 	return 0;
763 }
764 
765 #define CANNOT_SEND_MODERATED 1
766 #define CANNOT_SEND_NOPRIVMSGS 2
767 #define CANNOT_SEND_NOCOLOR 3
768 #define CANNOT_SEND_BAN 4
769 #define CANNOT_SEND_NOCTCP 5
770 #define CANNOT_SEND_MODREG 6
771 #define CANNOT_SEND_SWEAR 7 /* This isn't actually used here */
772 #define CANNOT_SEND_NOTICE 8
773 
can_send(aClient * cptr,aChannel * chptr,char * msgtext,int notice)774 int  can_send(aClient *cptr, aChannel *chptr, char *msgtext, int notice)
775 {
776 	Membership *lp;
777 	int  member;
778 	/*
779 	 * #0000053 by |savage|, speedup
780 	*/
781 
782 	if (!MyClient(cptr))
783 	{
784 		if (IsClient(cptr))
785 		{
786 			/* channelmode +mu is a special case.. sux!. -- Syzop */
787 
788 			lp = find_membership_link(cptr->user->channel, chptr);
789 			if ((chptr->mode.mode & MODE_MODERATED) && (chptr->mode.mode & MODE_AUDITORIUM) &&
790 			    !IsOper(cptr) &&
791 		        (!lp || !(lp->flags & (CHFL_CHANOP|CHFL_VOICE|CHFL_CHANOWNER|CHFL_HALFOP|CHFL_CHANPROT))) &&
792 		        !is_irc_banned(chptr))
793 		    {
794 				sendto_chmodemucrap(cptr, chptr, msgtext);
795 				return (CANNOT_SEND_MODERATED);
796 			}
797 		}
798 		return 0;
799 	}
800 
801 	if (chptr->mode.mode & MODE_NOCOLOR)
802 	{
803 		/* A bit faster */
804 		char *c;
805 		for (c = msgtext; *c; c++)
806 		{
807 			if (*c == 3 || *c == 27 || *c == 4 || *c == 22) /* mirc color, ansi, rgb, reverse */
808 				return (CANNOT_SEND_NOCOLOR);
809 		}
810 	}
811 	member = IsMember(cptr, chptr);
812 	if (chptr->mode.mode & MODE_NOPRIVMSGS && !member)
813 		return (CANNOT_SEND_NOPRIVMSGS);
814 
815 	lp = find_membership_link(cptr->user->channel, chptr);
816 	if ((chptr->mode.mode & MODE_MODREG) && !op_can_override(cptr) && !IsLoggedIn(cptr) &&
817 	    (!lp
818 	    || !(lp->flags & (CHFL_CHANOP | CHFL_VOICE | CHFL_CHANOWNER |
819 	    CHFL_HALFOP | CHFL_CHANPROT))))
820 		return CANNOT_SEND_MODREG;
821 	if (chptr->mode.mode & MODE_MODERATED && !op_can_override(cptr) &&
822 	    (!lp
823 	    || !(lp->flags & (CHFL_CHANOP | CHFL_VOICE | CHFL_CHANOWNER |
824 	    CHFL_HALFOP | CHFL_CHANPROT))))
825 	    {
826 			if ((chptr->mode.mode & MODE_AUDITORIUM) && !is_irc_banned(chptr) && !is_banned(cptr, chptr, BANCHK_MSG))
827 				sendto_chmodemucrap(cptr, chptr, msgtext);
828 			return (CANNOT_SEND_MODERATED);
829 	    }
830 
831 	if (chptr->mode.mode & MODE_NOCTCP &&
832 	    (!lp
833 	    || !(lp->flags & (CHFL_CHANOP | CHFL_CHANOWNER | CHFL_CHANPROT))))
834 		if (msgtext[0] == 1 && strncmp(&msgtext[1], "ACTION ", 7))
835 			return (CANNOT_SEND_NOCTCP);
836 
837 #ifdef EXTCMODE
838 	if (notice && (chptr->mode.extmode & EXTMODE_NONOTICE) &&
839 	   (!lp || !(lp->flags & (CHFL_CHANOP | CHFL_CHANOWNER | CHFL_CHANPROT))))
840 		return (CANNOT_SEND_NOTICE);
841 #endif
842 
843 
844 	/* Makes opers able to talk thru bans -Stskeeps suggested by The_Cat */
845 	if (IsOper(cptr))
846 		return 0;
847 
848 	if ((!lp
849 	    || !(lp->flags & (CHFL_CHANOP | CHFL_VOICE | CHFL_CHANOWNER |
850 	    CHFL_HALFOP | CHFL_CHANPROT))) && MyClient(cptr)
851 	    && is_banned(cptr, chptr, BANCHK_MSG))
852 		return (CANNOT_SEND_BAN);
853 
854 	return 0;
855 }
856 
857 /* [just a helper for channel_modef_string()] */
chmodefstrhelper(char * buf,char t,char tdef,unsigned short l,unsigned char a,unsigned char r)858 static inline char *chmodefstrhelper(char *buf, char t, char tdef, unsigned short l, unsigned char a, unsigned char r)
859 {
860 char *p;
861 char tmpbuf[16], *p2 = tmpbuf;
862 
863 	ircsprintf(buf, "%hd", l);
864 	p = buf + strlen(buf);
865 	*p++ = t;
866 	if (a && ((a != tdef) || r))
867 	{
868 		*p++ = '#';
869 		*p++ = a;
870 		if (r)
871 		{
872 			sprintf(tmpbuf, "%hd", (short)r);
873 			while ((*p = *p2++))
874 				p++;
875 		}
876 	}
877 	*p++ = ',';
878 	return p;
879 }
880 
881 /** returns the channelmode +f string (ie: '[5k,40j]:10') */
channel_modef_string(ChanFloodProt * x)882 char *channel_modef_string(ChanFloodProt *x)
883 {
884 static char retbuf[512]; /* overkill :p */
885 char *p = retbuf;
886 	*p++ = '[';
887 
888 	/* (alphabetized) */
889 	if (x->l[FLD_CTCP])
890 		p = chmodefstrhelper(p, 'c', 'C', x->l[FLD_CTCP], x->a[FLD_CTCP], x->r[FLD_CTCP]);
891 	if (x->l[FLD_JOIN])
892 		p = chmodefstrhelper(p, 'j', 'i', x->l[FLD_JOIN], x->a[FLD_JOIN], x->r[FLD_JOIN]);
893 	if (x->l[FLD_KNOCK])
894 		p = chmodefstrhelper(p, 'k', 'K', x->l[FLD_KNOCK], x->a[FLD_KNOCK], x->r[FLD_KNOCK]);
895 	if (x->l[FLD_MSG])
896 		p = chmodefstrhelper(p, 'm', 'm', x->l[FLD_MSG], x->a[FLD_MSG], x->r[FLD_MSG]);
897 	if (x->l[FLD_NICK])
898 		p = chmodefstrhelper(p, 'n', 'N', x->l[FLD_NICK], x->a[FLD_NICK], x->r[FLD_NICK]);
899 	if (x->l[FLD_TEXT])
900 		p = chmodefstrhelper(p, 't', '\0', x->l[FLD_TEXT], x->a[FLD_TEXT], x->r[FLD_TEXT]);
901 
902 	if (*(p - 1) == ',')
903 		p--;
904 	*p++ = ']';
905 	ircsprintf(p, ":%hd", x->per);
906 	return retbuf;
907 }
908 
909 /*
910  * write the "simple" list of channel modes for channel chptr onto buffer mbuf
911  * with the parameters in pbuf.
912  */
channel_modes(aClient * cptr,char * mbuf,char * pbuf,aChannel * chptr)913 void channel_modes(aClient *cptr, char *mbuf, char *pbuf, aChannel *chptr)
914 {
915 	aCtab *tab = &cFlagTab[0];
916 	char bcbuf[1024];
917 	int ismember;
918 #ifdef EXTCMODE
919 	int i;
920 #endif
921 
922 	ismember = (IsMember(cptr, chptr) || IsServer(cptr) || IsULine(cptr)) ? 1 : 0;
923 
924 	*pbuf = '\0';
925 
926 	*mbuf++ = '+';
927 	/* Paramless first */
928 	while (tab->mode != 0x0)
929 	{
930 		if ((chptr->mode.mode & tab->mode))
931 			if (!tab->parameters)
932 				*mbuf++ = tab->flag;
933 		tab++;
934 	}
935 #ifdef EXTCMODE
936 	for (i=0; i <= Channelmode_highest; i++)
937 	{
938 		if (Channelmode_Table[i].flag && !Channelmode_Table[i].paracount &&
939 		    (chptr->mode.extmode & Channelmode_Table[i].mode))
940 			*mbuf++ = Channelmode_Table[i].flag;
941 	}
942 #endif
943 	if (chptr->mode.limit)
944 	{
945 		*mbuf++ = 'l';
946 		if (ismember)
947 			(void)ircsprintf(pbuf, "%d ", chptr->mode.limit);
948 	}
949 	if (*chptr->mode.key)
950 	{
951 		*mbuf++ = 'k';
952 		if (ismember)
953 		{
954 			/* FIXME: hope pbuf is long enough */
955 			(void)snprintf(bcbuf, sizeof bcbuf, "%s ", chptr->mode.key);
956 			(void)strcat(pbuf, bcbuf);
957 		}
958 	}
959 	if (*chptr->mode.link)
960 	{
961 		*mbuf++ = 'L';
962 		if (ismember)
963 		{
964 			/* FIXME: is pbuf long enough?  */
965 			(void)snprintf(bcbuf, sizeof bcbuf, "%s ", chptr->mode.link);
966 			(void)strcat(pbuf, bcbuf);
967 		}
968 	}
969 	/* if we add more parameter modes, add a space to the strings here --Stskeeps */
970 #ifdef NEWCHFLOODPROT
971 	if (chptr->mode.floodprot)
972 #else
973 	if (chptr->mode.per)
974 #endif
975 	{
976 		*mbuf++ = 'f';
977 		if (ismember)
978 		{
979 #ifdef NEWCHFLOODPROT
980 			ircsprintf(bcbuf, "%s ", channel_modef_string(chptr->mode.floodprot));
981 #else
982 			if (chptr->mode.kmode == 1)
983 				ircsprintf(bcbuf, "*%i:%i ", chptr->mode.msgs, chptr->mode.per);
984 			else
985 				ircsprintf(bcbuf, "%i:%i ", chptr->mode.msgs, chptr->mode.per);
986 #endif
987 			(void)strcat(pbuf, bcbuf);
988 		}
989 	}
990 
991 #ifdef EXTCMODE
992 	for (i=0; i <= Channelmode_highest; i++)
993 	{
994 		if (Channelmode_Table[i].flag && Channelmode_Table[i].paracount &&
995 		    (chptr->mode.extmode & Channelmode_Table[i].mode))
996 		{
997 			*mbuf++ = Channelmode_Table[i].flag;
998 			if (ismember)
999 			{
1000 				strcat(pbuf, Channelmode_Table[i].get_param(extcmode_get_struct(chptr->mode.extmodeparam, Channelmode_Table[i].flag)));
1001 				strcat(pbuf, " ");
1002 			}
1003 		}
1004 	}
1005 #endif
1006 
1007 	/* Remove the trailing space from the parameters -- codemastr */
1008 	if (*pbuf)
1009 		pbuf[strlen(pbuf)-1]=0;
1010 
1011 	*mbuf++ = '\0';
1012 	return;
1013 }
1014 
1015 
DoesOp(char * modebuf)1016 int  DoesOp(char *modebuf)
1017 {
1018 	modebuf--;		/* Is it possible that a mode starts with o and not +o ? */
1019 	while (*++modebuf)
1020 		if (*modebuf == 'h' || *modebuf == 'o'
1021 		    || *modebuf == 'v' || *modebuf == 'q')
1022 			return (1);
1023 	return 0;
1024 }
1025 
sendmodeto_one(aClient * cptr,char * from,char * name,char * mode,char * param,TS creationtime)1026 int  sendmodeto_one(aClient *cptr, char *from, char *name, char *mode, char *param, TS creationtime)
1027 {
1028 	if ((IsServer(cptr) && DoesOp(mode) && creationtime) ||
1029 	    IsULine(cptr))
1030 		sendto_one(cptr, ":%s %s %s %s %s %lu", from,
1031 		    (IsToken(cptr) ? TOK_MODE : MSG_MODE), name, mode,
1032 		    param, creationtime);
1033 	else
1034 		sendto_one(cptr, ":%s %s %s %s %s", from,
1035 		    (IsToken(cptr) ? TOK_MODE : MSG_MODE), name, mode, param);
1036 	return 0;
1037 }
1038 
pretty_mask(char * mask)1039 char *pretty_mask(char *mask)
1040 {
1041 	char *cp;
1042 	char *user;
1043 	char *host;
1044 
1045 	if ((user = index((cp = mask), '!')))
1046 		*user++ = '\0';
1047 	if ((host = rindex(user ? user : cp, '@')))
1048 	{
1049 		*host++ = '\0';
1050 		if (!user)
1051 			return make_nick_user_host(NULL, cp, host);
1052 	}
1053 	else if (!user && index(cp, '.'))
1054 		return make_nick_user_host(NULL, NULL, cp);
1055 	return make_nick_user_host(cp, user, host);
1056 }
1057 
trim_str(char * str,int len)1058 char *trim_str(char *str, int len)
1059 {
1060 	int l;
1061 	if (!str)
1062 		return NULL;
1063 	if ((l = strlen(str)) > len)
1064 	{
1065 		str += l - len;
1066 		*str = '*';
1067 	}
1068 	return str;
1069 }
1070 
1071 /* clean_ban_mask:	makes a proper banmask
1072  * RETURNS: pointer to correct banmask or NULL in case of error
1073  * NOTES:
1074  * - A pointer is returned to a static buffer, which is overwritten
1075  *   on next clean_ban_mask or make_nick_user_host call.
1076  * - mask is fragged in some cases, this could be bad.
1077  */
clean_ban_mask(char * mask,int what,aClient * cptr)1078 char *clean_ban_mask(char *mask, int what, aClient *cptr)
1079 {
1080 	char *cp;
1081 	char *user;
1082 	char *host;
1083 	Extban *p;
1084 
1085 	cp = index(mask, ' ');
1086 	if (cp)
1087 		*cp = '\0';
1088 
1089 	/* Strip any ':' at beginning coz that desynchs clients/banlists */
1090 	for (; (*mask && (*mask == ':')); mask++);
1091 	if (!*mask)
1092 		return NULL;
1093 
1094 	/* Extended ban? */
1095 	if ((*mask == '~') && mask[1] && (mask[2] == ':'))
1096 	{
1097 		if (RESTRICT_EXTENDEDBANS && MyClient(cptr) && !IsAnOper(cptr))
1098 		{
1099 			if (!strcmp(RESTRICT_EXTENDEDBANS, "*"))
1100 			{
1101 				sendnotice(cptr, "Setting/removing of extended bans has been disabled");
1102 				return NULL;
1103 			}
1104 			if (strchr(RESTRICT_EXTENDEDBANS, mask[1]))
1105 			{
1106 				sendnotice(cptr, "Setting/removing of extended bantypes '%s' has been disabled",
1107 					RESTRICT_EXTENDEDBANS);
1108 				return NULL;
1109 			}
1110 		}
1111 		p = findmod_by_bantype(mask[1]);
1112 		if (!p)
1113 		{
1114 			/* extended bantype not supported, what to do?
1115 			 * Here are the rules:
1116 			 * - if from a remote client/server: allow it (easy upgrading,
1117 			 *   no desynch)
1118 			 * - if from a local client trying to REMOVE the extban,
1119 			 *   allow it too (so you don't get "unremovable" extbans).
1120 			 */
1121 			if (!MyClient(cptr) || (what == MODE_DEL))
1122 				return mask; /* allow it */
1123 			return NULL; /* reject */
1124 		}
1125 		if (p->conv_param)
1126 			return p->conv_param(mask);
1127 		/* else, do some basic sanity checks and cut it off at 80 bytes */
1128 		if ((cp[1] != ':') || (cp[2] == '\0'))
1129 		    return NULL; /* require a ":<char>" after extban type */
1130 		if (strlen(mask) > 80)
1131 			mask[80] = '\0';
1132 		return mask;
1133 	}
1134 
1135 	if ((*mask == '~') && !strchr(mask, '@'))
1136 		return NULL; /* not an extended ban and not a ~user@host ban either. */
1137 
1138 	if ((user = index((cp = mask), '!')))
1139 		*user++ = '\0';
1140 	if ((host = rindex(user ? user : cp, '@')))
1141 	{
1142 		*host++ = '\0';
1143 
1144 		if (!user)
1145 			return make_nick_user_host(NULL, trim_str(cp,USERLEN),
1146 				trim_str(host,HOSTLEN));
1147 	}
1148 	else if (!user && index(cp, '.'))
1149 		return make_nick_user_host(NULL, NULL, trim_str(cp,HOSTLEN));
1150 	return make_nick_user_host(trim_str(cp,NICKLEN), trim_str(user,USERLEN),
1151 		trim_str(host,HOSTLEN));
1152 }
1153 
find_invex(aChannel * chptr,aClient * sptr)1154 int find_invex(aChannel *chptr, aClient *sptr)
1155 {
1156 	/* This routine is basically a copy-paste of is_banned_with_nick, with modifications, for invex */
1157 	Ban *inv;
1158 	char *s;
1159 	static char realhost[NICKLEN + USERLEN + HOSTLEN + 24];
1160 	static char cloakhost[NICKLEN + USERLEN + HOSTLEN + 24];
1161 	static char virthost[NICKLEN + USERLEN + HOSTLEN + 24];
1162 	static char     nuip[NICKLEN + USERLEN + HOSTLEN + 24];
1163 	Extban *extban;
1164 
1165 	if (!IsPerson(sptr) || !chptr->invexlist)
1166 		return 0;
1167 
1168 	ban_realhost = realhost;
1169 	ban_ip = ban_virthost = ban_cloakhost = NULL;
1170 
1171 	if (GetIP(sptr))
1172 	{
1173 		make_nick_user_host_r(nuip, sptr->name, sptr->user->username, GetIP(sptr));
1174 		ban_ip = nuip;
1175 	}
1176 
1177 	if (*sptr->user->cloakedhost)
1178 	{
1179 		make_nick_user_host_r(cloakhost, sptr->name, sptr->user->username, sptr->user->cloakedhost);
1180 		ban_cloakhost = cloakhost;
1181 	}
1182 
1183 	if (IsSetHost(sptr) && strcmp(sptr->user->realhost, sptr->user->virthost))
1184 	{
1185 		make_nick_user_host_r(virthost, sptr->name, sptr->user->username, sptr->user->virthost);
1186 		ban_virthost = virthost;
1187 	}
1188 
1189 
1190 	make_nick_user_host_r(realhost, sptr->name, sptr->user->username, sptr->user->realhost);
1191 
1192 	for (inv = chptr->invexlist; inv; inv = inv->next)
1193 		if (ban_check_mask(sptr, chptr, inv->banstr, BANCHK_JOIN, 0))
1194 			return 1;
1195 
1196 	return 0;
1197 }
1198 
1199 /*
1200 ** Remove bells and commas from channel name
1201 */
1202 
clean_channelname(char * cn)1203 void clean_channelname(char *cn)
1204 {
1205 	u_char *ch = (u_char *)cn;
1206 
1207 
1208 	for (; *ch; ch++)
1209 		/* Don't allow any control chars, the space, the comma,
1210 		 * or the "non-breaking space" in channel names.
1211 		 * Might later be changed to a system where the list of
1212 		 * allowed/non-allowed chars for channels was a define
1213 		 * or some such.
1214 		 *   --Wizzu
1215 		 */
1216 		if (*ch < 33 || *ch == ',' || *ch == 160)
1217 		{
1218 			*ch = '\0';
1219 			return;
1220 		}
1221 }
1222 
1223 /*
1224 ** Return -1 if mask is present and doesnt match our server name.
1225 */
check_channelmask(aClient * sptr,aClient * cptr,char * chname)1226 int check_channelmask(aClient *sptr, aClient *cptr, char *chname)
1227 {
1228 	char *s;
1229 
1230 	s = rindex(chname, ':');
1231 	if (!s)
1232 		return 0;
1233 
1234 	s++;
1235 	if (match(s, me.name) || (IsServer(cptr) && match(s, cptr->name)))
1236 	{
1237 		if (MyClient(sptr))
1238 			sendto_one(sptr, err_str(ERR_BADCHANMASK),
1239 			    me.name, sptr->name, chname);
1240 		return -1;
1241 	}
1242 	return 0;
1243 }
1244 
1245 /*
1246 **  Get Channel block for i (and allocate a new channel
1247 **  block, if it didn't exists before).
1248 */
get_channel(aClient * cptr,char * chname,int flag)1249 aChannel *get_channel(aClient *cptr, char *chname, int flag)
1250 {
1251 	aChannel *chptr;
1252 	int  len;
1253 
1254 	if (BadPtr(chname))
1255 		return NULL;
1256 
1257 	len = strlen(chname);
1258 	if (MyClient(cptr) && len > CHANNELLEN)
1259 	{
1260 		len = CHANNELLEN;
1261 		*(chname + CHANNELLEN) = '\0';
1262 	}
1263 	if ((chptr = find_channel(chname, (aChannel *)NULL)))
1264 		return (chptr);
1265 	if (flag == CREATE)
1266 	{
1267 		chptr = (aChannel *)MyMalloc(sizeof(aChannel) + len);
1268 		bzero((char *)chptr, sizeof(aChannel));
1269 		strncpyzt(chptr->chname, chname, len + 1);
1270 		if (channel)
1271 			channel->prevch = chptr;
1272 		chptr->topic = NULL;
1273 		chptr->topic_nick = NULL;
1274 		chptr->prevch = NULL;
1275 		chptr->nextch = channel;
1276 		chptr->creationtime = MyClient(cptr) ? TStime() : (TS)0;
1277 		channel = chptr;
1278 		(void)add_to_channel_hash_table(chname, chptr);
1279 		IRCstats.channels++;
1280 		RunHook2(HOOKTYPE_CHANNEL_CREATE, cptr, chptr);
1281 	}
1282 	return chptr;
1283 }
1284 
1285 /*
1286  * Slight changes in routine, now working somewhat symmetrical:
1287  *   First try to remove the client & channel pair to avoid duplicates
1288  *   Second check client & channel invite-list lengths and remove tail
1289  *   Finally add new invite-links to both client and channel
1290  * Should U-lined clients have higher limits?   -Donwulff
1291  */
1292 
add_invite(aClient * cptr,aChannel * chptr)1293 void add_invite(aClient *cptr, aChannel *chptr)
1294 {
1295 	Link *inv, *tmp;
1296 
1297 	del_invite(cptr, chptr);
1298 	/*
1299 	 * delete last link in chain if the list is max length
1300 	 */
1301 	if (list_length(cptr->user->invited) >= MAXCHANNELSPERUSER)
1302 	{
1303 /*		This forgets the channel side of invitation     -Vesa
1304 		inv = cptr->user->invited;
1305 		cptr->user->invited = inv->next;
1306 		free_link(inv);
1307 */
1308 		for (tmp = cptr->user->invited; tmp->next; tmp = tmp->next)
1309 			;
1310 		del_invite(cptr, tmp->value.chptr);
1311 
1312 	}
1313 	/* We get pissy over too many invites per channel as well now,
1314 	 * since otherwise mass-inviters could take up some major
1315 	 * resources -Donwulff
1316 	 */
1317 	if (list_length(chptr->invites) >= MAXCHANNELSPERUSER)
1318 	{
1319 		for (tmp = chptr->invites; tmp->next; tmp = tmp->next)
1320 			;
1321 		del_invite(tmp->value.cptr, chptr);
1322 	}
1323 	/*
1324 	 * add client to the beginning of the channel invite list
1325 	 */
1326 	inv = make_link();
1327 	inv->value.cptr = cptr;
1328 	inv->next = chptr->invites;
1329 	chptr->invites = inv;
1330 	/*
1331 	 * add channel to the beginning of the client invite list
1332 	 */
1333 	inv = make_link();
1334 	inv->value.chptr = chptr;
1335 	inv->next = cptr->user->invited;
1336 	cptr->user->invited = inv;
1337 }
1338 
1339 /*
1340  * Delete Invite block from channel invite list and client invite list
1341  */
del_invite(aClient * cptr,aChannel * chptr)1342 void del_invite(aClient *cptr, aChannel *chptr)
1343 {
1344 	Link **inv, *tmp;
1345 
1346 	for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1347 		if (tmp->value.cptr == cptr)
1348 		{
1349 			*inv = tmp->next;
1350 			free_link(tmp);
1351 			break;
1352 		}
1353 
1354 	for (inv = &(cptr->user->invited); (tmp = *inv); inv = &tmp->next)
1355 		if (tmp->value.chptr == chptr)
1356 		{
1357 			*inv = tmp->next;
1358 			free_link(tmp);
1359 			break;
1360 		}
1361 }
1362 
1363 /*
1364 **  Subtract one user from channel i (and free channel
1365 **  block, if channel became empty).
1366 */
sub1_from_channel(aChannel * chptr)1367 void sub1_from_channel(aChannel *chptr)
1368 {
1369 	Ban *ban;
1370 	Link *lp;
1371 
1372         /* if (--chptr->users <= 0) */
1373 	if (chptr->users == 0 || --chptr->users == 0)
1374 	{
1375 		/*
1376 		 * Now, find all invite links from channel structure
1377 		 */
1378 		RunHook(HOOKTYPE_CHANNEL_DESTROY, chptr);
1379 		while ((lp = chptr->invites))
1380 			del_invite(lp->value.cptr, chptr);
1381 
1382 		while (chptr->banlist)
1383 		{
1384 			ban = chptr->banlist;
1385 			chptr->banlist = ban->next;
1386 			MyFree(ban->banstr);
1387 			MyFree(ban->who);
1388 			free_ban(ban);
1389 		}
1390 		while (chptr->exlist)
1391 		{
1392 			ban = chptr->exlist;
1393 			chptr->exlist = ban->next;
1394 			MyFree(ban->banstr);
1395 			MyFree(ban->who);
1396 			free_ban(ban);
1397 		}
1398 		while (chptr->invexlist)
1399 		{
1400 			ban = chptr->invexlist;
1401 			chptr->invexlist = ban->next;
1402 			MyFree(ban->banstr);
1403 			MyFree(ban->who);
1404 			free_ban(ban);
1405 		}
1406 #ifdef EXTCMODE
1407 		/* free extcmode params */
1408 		extcmode_free_paramlist(chptr->mode.extmodeparam);
1409 		chptr->mode.extmodeparam = NULL;
1410 #endif
1411 #ifdef NEWCHFLOODPROT
1412 		chanfloodtimer_stopchantimers(chptr);
1413 		if (chptr->mode.floodprot)
1414 			MyFree(chptr->mode.floodprot);
1415 #endif
1416 #ifdef JOINTHROTTLE
1417 		cmodej_delchannelentries(chptr);
1418 #endif
1419 		if (chptr->mode_lock)
1420 			MyFree(chptr->mode_lock);
1421 		if (chptr->topic)
1422 			MyFree(chptr->topic);
1423 		if (chptr->topic_nick)
1424 			MyFree(chptr->topic_nick);
1425 		if (chptr->prevch)
1426 			chptr->prevch->nextch = chptr->nextch;
1427 		else
1428 			channel = chptr->nextch;
1429 		if (chptr->nextch)
1430 			chptr->nextch->prevch = chptr->prevch;
1431 		(void)del_from_channel_hash_table(chptr->chname, chptr);
1432 		IRCstats.channels--;
1433 		MyFree((char *)chptr);
1434 	}
1435 }
1436 
check_for_chan_flood(aClient * cptr,aClient * sptr,aChannel * chptr)1437 int  check_for_chan_flood(aClient *cptr, aClient *sptr, aChannel *chptr)
1438 {
1439 	Membership *lp;
1440 	MembershipL *lp2;
1441 	int c_limit, t_limit, banthem;
1442 
1443 	if (!MyClient(sptr))
1444 		return 0;
1445 	if (IsOper(sptr) || IsULine(sptr))
1446 		return 0;
1447 	if (is_skochanop(sptr, chptr))
1448 		return 0;
1449 
1450 	if (!(lp = find_membership_link(sptr->user->channel, chptr)))
1451 		return 0;
1452 
1453 	lp2 = (MembershipL *) lp;
1454 
1455 #ifdef NEWCHFLOODPROT
1456 	if (!chptr->mode.floodprot || !chptr->mode.floodprot->l[FLD_TEXT])
1457 		return 0;
1458 	c_limit = chptr->mode.floodprot->l[FLD_TEXT];
1459 	t_limit = chptr->mode.floodprot->per;
1460 	banthem = (chptr->mode.floodprot->a[FLD_TEXT] == 'b') ? 1 : 0;
1461 #else
1462 	if ((chptr->mode.msgs < 1) || (chptr->mode.per < 1))
1463 		return 0;
1464 	c_limit = chptr->mode.msgs;
1465 	t_limit = chptr->mode.per;
1466 	banthem = chptr->mode.kmode;
1467 #endif
1468 	/* if current - firstmsgtime >= mode.per, then reset,
1469 	 * if nummsg > mode.msgs then kick/ban
1470 	 */
1471 	Debug((DEBUG_ERROR, "Checking for flood +f: firstmsg=%d (%ds ago), new nmsgs: %d, limit is: %d:%d",
1472 		lp2->flood.firstmsg, TStime() - lp2->flood.firstmsg, lp2->flood.nmsg + 1,
1473 		c_limit, t_limit));
1474 	if ((TStime() - lp2->flood.firstmsg) >= t_limit)
1475 	{
1476 		/* reset */
1477 		lp2->flood.firstmsg = TStime();
1478 		lp2->flood.nmsg = 1;
1479 		return 0; /* forget about it.. */
1480 	}
1481 
1482 	/* increase msgs */
1483 	lp2->flood.nmsg++;
1484 
1485 	if ((lp2->flood.nmsg) > c_limit)
1486 	{
1487 		char comment[1024], mask[1024];
1488 		ircsprintf(comment,
1489 		    "Flooding (Limit is %i lines per %i seconds)",
1490 		    c_limit, t_limit);
1491 		if (banthem)
1492 		{		/* ban. */
1493 			ircsprintf(mask, "*!*@%s", GetHost(sptr));
1494 			add_listmode(&chptr->banlist, &me, chptr, mask);
1495 			sendto_serv_butone(&me, ":%s MODE %s +b %s 0",
1496 			    me.name, chptr->chname, mask);
1497 			sendto_channel_butserv(chptr, &me,
1498 			    ":%s MODE %s +b %s", me.name, chptr->chname, mask);
1499 		}
1500 		sendto_channel_butserv(chptr, &me,
1501 		    ":%s KICK %s %s :%s", me.name,
1502 		    chptr->chname, sptr->name, comment);
1503 		sendto_serv_butone_token(cptr, me.name,
1504 			MSG_KICK, TOK_KICK,
1505 			"%s %s :%s",
1506 		   chptr->chname, sptr->name, comment);
1507 		remove_user_from_channel(sptr, chptr);
1508 		return 1;
1509 	}
1510 	return 0;
1511 }
1512 
send_user_joins(aClient * cptr,aClient * user)1513 void send_user_joins(aClient *cptr, aClient *user)
1514 {
1515 	Membership *lp;
1516 	aChannel *chptr;
1517 	int  cnt = 0, len = 0, clen;
1518 	char *mask;
1519 
1520 	snprintf(buf, sizeof buf, ":%s %s ", user->name,
1521 	    (IsToken(cptr) ? TOK_JOIN : MSG_JOIN));
1522 	len = strlen(buf);
1523 
1524 	for (lp = user->user->channel; lp; lp = lp->next)
1525 	{
1526 		chptr = lp->chptr;
1527 		if ((mask = index(chptr->chname, ':')))
1528 			if (match(++mask, cptr->name))
1529 				continue;
1530 		if (*chptr->chname == '&')
1531 			continue;
1532 		clen = strlen(chptr->chname);
1533 		if (clen + 1 + len > BUFSIZE - 3)
1534 		{
1535 			if (cnt)
1536 			{
1537 				buf[len - 1] = '\0';
1538 				sendto_one(cptr, "%s", buf);
1539 			}
1540 			snprintf(buf, sizeof buf, ":%s %s ", user->name,
1541 			    (IsToken(cptr) ? TOK_JOIN : MSG_JOIN));
1542 			len = strlen(buf);
1543 			cnt = 0;
1544 		}
1545 		(void)strlcpy(buf + len, chptr->chname, sizeof buf-len);
1546 		cnt++;
1547 		len += clen;
1548 		if (lp->next)
1549 		{
1550 			len++;
1551 			(void)strlcat(buf, ",", sizeof buf);
1552 		}
1553 	}
1554 	if (*buf && cnt)
1555 		sendto_one(cptr, "%s", buf);
1556 
1557 	return;
1558 }
1559 
1560 /*
1561  * rejoin_doparts:
1562  * sends a PART to all channels (to local users only)
1563  */
rejoin_doparts(aClient * sptr,char did_parts[])1564 void rejoin_doparts(aClient *sptr, char did_parts[])
1565 {
1566 	Membership *tmp;
1567 	aChannel *chptr;
1568 	char *comment = "Rejoining because of user@host change";
1569 	int i = 0;
1570 
1571 	for (tmp = sptr->user->channel; tmp; tmp = tmp->next)
1572 	{
1573 		chptr = tmp->chptr;
1574 		if (!chptr)
1575 			continue; /* Possible? */
1576 
1577 		/* If the user is banned, don't do it */
1578 		if (is_banned(sptr, chptr, BANCHK_JOIN))
1579 		{
1580 			did_parts[i++] = 0;
1581 			continue;
1582 		}
1583 		did_parts[i++] = 1;
1584 
1585 		if ((chptr->mode.mode & MODE_AUDITORIUM) &&
1586 		    !(tmp->flags & (CHFL_CHANOWNER|CHFL_CHANPROT|CHFL_CHANOP)))
1587 		{
1588 			sendto_chanops_butone(sptr, chptr, ":%s!%s@%s PART %s :%s", sptr->name, sptr->user->username, GetHost(sptr), chptr->chname, comment);
1589 		} else
1590 			sendto_channel_butserv_butone(chptr, sptr, sptr, ":%s PART %s :%s", sptr->name, chptr->chname, comment);
1591 	}
1592 }
1593 
1594 /*
1595  * rejoin_dojoinandmode:
1596  * sends a JOIN and a MODE (if needed) to restore qaohv modes (to local users only)
1597  */
rejoin_dojoinandmode(aClient * sptr,char did_parts[])1598 void rejoin_dojoinandmode(aClient *sptr, char did_parts[])
1599 {
1600 	Membership *tmp;
1601 	aChannel *chptr;
1602 	int i, j = 0, n, flags;
1603 	char flagbuf[8]; /* For holding "qohva" and "*~@%+" */
1604 
1605 	for (tmp = sptr->user->channel; tmp; tmp = tmp->next)
1606 	{
1607 		flags = tmp->flags;
1608 		chptr = tmp->chptr;
1609 		if (!chptr)
1610 			continue; /* Is it possible? */
1611 
1612 		/* If the user is banned, don't do it */
1613 		if (!did_parts[j++])
1614 			continue;
1615 
1616 		if ((chptr->mode.mode & MODE_AUDITORIUM) &&
1617 		    !(flags & (CHFL_CHANOWNER|CHFL_CHANPROT|CHFL_CHANOP)))
1618 		{
1619 			sendto_chanops_butone(sptr, chptr, ":%s!%s@%s JOIN :%s", sptr->name, sptr->user->username, GetHost(sptr), chptr->chname);
1620 		} else
1621 			sendto_channel_butserv_butone(chptr, sptr, sptr, ":%s JOIN :%s", sptr->name, chptr->chname);
1622 
1623 		/* Set the modes (if any) */
1624 		if (flags)
1625 		{
1626 			char *p = flagbuf;
1627 			if (flags & MODE_CHANOP)
1628 				*p++ = 'o';
1629 			if (flags & MODE_VOICE)
1630 				*p++ = 'v';
1631 			if (flags & MODE_HALFOP)
1632 				*p++ = 'h';
1633 			if (flags & MODE_CHANOWNER)
1634 				*p++ = 'q';
1635 			if (flags & MODE_CHANPROT)
1636 				*p++ = 'a';
1637 			*p = '\0';
1638 			parabuf[0] = '\0';
1639 			n = strlen(flagbuf);
1640 			if (n)
1641 			{
1642 				for (i=0; i < n; i++)
1643 				{
1644 					strcat(parabuf, sptr->name);
1645 					if (i < n - 1)
1646 						strcat(parabuf, " ");
1647 				}
1648 				sendto_channel_butserv_butone(chptr, &me, sptr, ":%s MODE %s +%s %s",
1649 					me.name, chptr->chname, flagbuf, parabuf);
1650 			}
1651 		}
1652 	}
1653 }
1654 
1655 #ifdef NEWCHFLOODPROT
1656 MODVAR RemoveFld *removefld_list = NULL;
1657 
chanfloodtimer_find(aChannel * chptr,char mflag)1658 RemoveFld *chanfloodtimer_find(aChannel *chptr, char mflag)
1659 {
1660 RemoveFld *e;
1661 
1662 	for (e=removefld_list; e; e=e->next)
1663 	{
1664 		if ((e->chptr == chptr) && (e->m == mflag))
1665 			return e;
1666 	}
1667 	return NULL;
1668 }
1669 
1670 /*
1671  * Adds a "remove channelmode set by +f" timer.
1672  * chptr	Channel
1673  * mflag	Mode flag, eg 'C'
1674  * mbit		Mode bitflag, eg MODE_NOCTCP
1675  * when		when it should be removed
1676  * NOTES:
1677  * - This function takes care of overwriting of any previous timer
1678  *   for the same modechar.
1679  * - The function takes care of chptr->mode.floodprot->timer_flags,
1680  *   do not modify it yourself.
1681  * - chptr->mode.floodprot is asumed to be non-NULL.
1682  */
chanfloodtimer_add(aChannel * chptr,char mflag,long mbit,time_t when)1683 void chanfloodtimer_add(aChannel *chptr, char mflag, long mbit, time_t when)
1684 {
1685 RemoveFld *e = NULL;
1686 unsigned char add=1;
1687 
1688 	if (chptr->mode.floodprot->timer_flags & mbit)
1689 	{
1690 		/* Already exists... */
1691 		e = chanfloodtimer_find(chptr, mflag);
1692 		if (e)
1693 			add = 0;
1694 	}
1695 
1696 	if (add)
1697 		e = MyMallocEx(sizeof(RemoveFld));
1698 
1699 	e->chptr = chptr;
1700 	e->m = mflag;
1701 	e->when = when;
1702 
1703 	if (add)
1704 		AddListItem(e, removefld_list);
1705 
1706 	chptr->mode.floodprot->timer_flags |= mbit;
1707 }
1708 
chanfloodtimer_del(aChannel * chptr,char mflag,long mbit)1709 void chanfloodtimer_del(aChannel *chptr, char mflag, long mbit)
1710 {
1711 RemoveFld *e;
1712 
1713 	if (chptr->mode.floodprot && !(chptr->mode.floodprot->timer_flags & mbit))
1714 		return; /* nothing to remove.. */
1715 	e = chanfloodtimer_find(chptr, mflag);
1716 	if (!e)
1717 		return;
1718 
1719 	DelListItem(e, removefld_list);
1720 
1721 	if (chptr->mode.floodprot)
1722 		chptr->mode.floodprot->timer_flags &= ~mbit;
1723 }
1724 
get_chanbitbychar(char m)1725 long get_chanbitbychar(char m)
1726 {
1727 aCtab *tab = &cFlagTab[0];
1728 	while(tab->mode != 0x0)
1729 	{
1730 		if (tab->flag == m)
1731 			return tab->mode;
1732 		tab++;;
1733 	}
1734 	return 0;
1735 }
1736 
EVENT(modef_event)1737 EVENT(modef_event)
1738 {
1739 RemoveFld *e = removefld_list;
1740 time_t now;
1741 long mode;
1742 
1743 	now = TStime();
1744 
1745 	while(e)
1746 	{
1747 		if (e->when <= now)
1748 		{
1749 			/* Remove chanmode... */
1750 #ifdef NEWFLDDBG
1751 			sendto_realops("modef_event: chan %s mode -%c EXPIRED", e->chptr->chname, e->m);
1752 #endif
1753 			mode = get_chanbitbychar(e->m);
1754 			if (e->chptr->mode.mode & mode)
1755 			{
1756 				sendto_serv_butone(&me, ":%s MODE %s -%c 0", me.name, e->chptr->chname, e->m);
1757 				sendto_channel_butserv(e->chptr, &me, ":%s MODE %s -%c", me.name, e->chptr->chname, e->m);
1758 				e->chptr->mode.mode &= ~mode;
1759 			}
1760 
1761 			/* And delete... */
1762 			e = (RemoveFld *)DelListItem(e, removefld_list);
1763 		} else {
1764 #ifdef NEWFLDDBG
1765 			sendto_realops("modef_event: chan %s mode -%c about %d seconds",
1766 				e->chptr->chname, e->m, e->when - now);
1767 #endif
1768 			e = e->next;
1769 		}
1770 	}
1771 }
1772 
init_modef()1773 void init_modef()
1774 {
1775 	EventAddEx(NULL, "modef_event", 10, 0, modef_event, NULL);
1776 }
1777 
chanfloodtimer_stopchantimers(aChannel * chptr)1778 void chanfloodtimer_stopchantimers(aChannel *chptr)
1779 {
1780 RemoveFld *e = removefld_list;
1781 	while(e)
1782 	{
1783 		if (e->chptr == chptr)
1784 			e = (RemoveFld *)DelListItem(e, removefld_list);
1785 		else
1786 			e = e->next;
1787 	}
1788 }
1789 
1790 
1791 
do_chanflood(ChanFloodProt * chp,int what)1792 int do_chanflood(ChanFloodProt *chp, int what)
1793 {
1794 
1795 	if (!chp || !chp->l[what]) /* no +f or not restricted */
1796 		return 0;
1797 	if (TStime() - chp->t[what] >= chp->per)
1798 	{
1799 		chp->t[what] = TStime();
1800 		chp->c[what] = 1;
1801 	} else
1802 	{
1803 		chp->c[what]++;
1804 		if ((chp->c[what] > chp->l[what]) &&
1805 		    (TStime() - chp->t[what] < chp->per))
1806 		{
1807 			/* reset it too (makes it easier for chanops to handle the situation) */
1808 			/*
1809 			 *XXchp->t[what] = TStime();
1810 			 *XXchp->c[what] = 1;
1811 			 *
1812 			 * BAD.. there are some situations where we might 'miss' a flood
1813 			 * because of this. The reset has been moved to -i,-m,-N,-C,etc.
1814 			*/
1815 			return 1; /* flood detected! */
1816 		}
1817 	}
1818 	return 0;
1819 }
1820 
do_chanflood_action(aChannel * chptr,int what,char * text)1821 void do_chanflood_action(aChannel *chptr, int what, char *text)
1822 {
1823 long modeflag = 0;
1824 aCtab *tab = &cFlagTab[0];
1825 char m;
1826 
1827 	m = chptr->mode.floodprot->a[what];
1828 	if (!m)
1829 		return;
1830 
1831 	/* [TODO: add extended channel mode support] */
1832 
1833 	while(tab->mode != 0x0)
1834 	{
1835 		if (tab->flag == m)
1836 		{
1837 			modeflag = tab->mode;
1838 			break;
1839 		}
1840 		tab++;
1841 	}
1842 
1843 	if (!modeflag)
1844 		return;
1845 
1846 	if (!(chptr->mode.mode & modeflag))
1847 	{
1848 		char comment[1024], target[CHANNELLEN + 8];
1849 		ircsprintf(comment, "*** Channel %sflood detected (limit is %d per %d seconds), setting mode +%c",
1850 			text, chptr->mode.floodprot->l[what], chptr->mode.floodprot->per, m);
1851 		ircsprintf(target, "%%%s", chptr->chname);
1852 		sendto_channelprefix_butone_tok(NULL, &me, chptr,
1853 			PREFIX_HALFOP|PREFIX_OP|PREFIX_ADMIN|PREFIX_OWNER,
1854 			MSG_NOTICE, TOK_NOTICE, target, comment, 0);
1855 		sendto_serv_butone(&me, ":%s MODE %s +%c 0", me.name, chptr->chname, m);
1856 		sendto_channel_butserv(chptr, &me, ":%s MODE %s +%c", me.name, chptr->chname, m);
1857 		chptr->mode.mode |= modeflag;
1858 		if (chptr->mode.floodprot->r[what]) /* Add remove-chanmode timer... */
1859 		{
1860 			chanfloodtimer_add(chptr, m, modeflag, TStime() + ((long)chptr->mode.floodprot->r[what] * 60) - 5);
1861 			/* (since the chanflood timer event is called every 10s, we do -5 here so the accurancy will
1862 			 *  be -5..+5, without it it would be 0..+10.)
1863 			 */
1864 		}
1865 	}
1866 }
1867 #endif
1868 
1869 /* set_channel_mlock()
1870  *
1871  * inputs	- client, source, channel, params
1872  * output	-
1873  * side effects - channel mlock is changed / MLOCK is propagated
1874  */
set_channel_mlock(aClient * cptr,aClient * sptr,aChannel * chptr,const char * newmlock,int propagate)1875 void set_channel_mlock(aClient *cptr, aClient *sptr, aChannel *chptr, const char *newmlock, int propagate)
1876 {
1877 	if (chptr->mode_lock)
1878 		MyFree(chptr->mode_lock);
1879 	chptr->mode_lock = (newmlock != NULL) ? strdup(newmlock) : NULL;
1880 
1881 	if (propagate)
1882 	{
1883 		sendto_serv_butone_token(cptr, cptr->name, MSG_MLOCK, TOK_MLOCK, "%B %s :%s",
1884 					 chptr->creationtime, chptr->chname,
1885 					 BadPtr(chptr->mode_lock) ? "" : chptr->mode_lock);
1886 	}
1887 }
1888