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