ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/channel.c
Revision: 69
Committed: Tue Oct 4 16:09:51 2005 UTC (20 years, 10 months ago) by adx
Content type: text/x-csrc
File size: 24875 byte(s)
Log Message:
- splitted ircd/libio, all headers connected with libio sources have been
  moved for internal use only. To use libio interface, include "libio.h"
  (which is already done in "stdinc.h")


File Contents

# User Rev Content
1 adx 30 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     *
4     * Copyright (C) 2002 by the past and present ircd coders, and others.
5     *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19     * USA
20     */
21    
22     /*! \file channel.c
23     * \brief Responsible for managing channels, members, bans and topics
24 knight 31 * \version $Id$
25 adx 30 */
26    
27     #include "stdinc.h"
28     #include "channel.h"
29     #include "channel_mode.h"
30     #include "client.h"
31     #include "common.h"
32     #include "hash.h"
33     #include "ircd.h"
34     #include "numeric.h"
35     #include "s_serv.h" /* captab */
36     #include "s_user.h"
37     #include "send.h"
38     #include "s_conf.h" /* ConfigFileEntry, ConfigChannel */
39    
40     struct config_channel_entry ConfigChannel;
41     dlink_list global_channel_list = { NULL, NULL, 0 };
42     dlink_list lazylink_channels = { NULL, NULL, 0 };
43     BlockHeap *ban_heap; /*! \todo ban_heap shouldn't be a global var */
44    
45     static BlockHeap *topic_heap = NULL;
46     static BlockHeap *member_heap = NULL;
47     static BlockHeap *channel_heap = NULL;
48    
49     static char buf[IRCD_BUFSIZE];
50     static char modebuf[MODEBUFLEN];
51     static char parabuf[MODEBUFLEN];
52    
53    
54     /*! \brief Initializes the channel blockheap, adds known channel CAPAB
55     */
56     void
57     init_channels(void)
58     {
59     /*
60     * XXX - These should get moved to somwhere else once we have
61     * a modular channelmode system
62     */
63     add_capability("EX", CAP_EX, 1);
64     add_capability("IE", CAP_IE, 1);
65     add_capability("CHW", CAP_CHW, 1);
66    
67     channel_heap = BlockHeapCreate("channel", sizeof(struct Channel), CHANNEL_HEAP_SIZE);
68     ban_heap = BlockHeapCreate("ban", sizeof(struct Ban), BAN_HEAP_SIZE);
69     topic_heap = BlockHeapCreate("topic", TOPICLEN+1 + USERHOST_REPLYLEN, TOPIC_HEAP_SIZE);
70     member_heap = BlockHeapCreate("member", sizeof(struct Membership), CHANNEL_HEAP_SIZE*2);
71     }
72    
73     /*! \brief adds a user to a channel by adding another link to the
74     * channels member chain.
75     * \param chptr pointer to channel to add client to
76     * \param who pointer to client (who) to add
77     * \param flags flags for chanops etc
78     * \param flood_ctrl whether to count this join in flood calculations
79     */
80     void
81     add_user_to_channel(struct Channel *chptr, struct Client *who,
82     unsigned int flags, int flood_ctrl)
83     {
84     struct Membership *ms = NULL;
85    
86     if (GlobalSetOptions.joinfloodtime > 0)
87     {
88     if (flood_ctrl)
89     chptr->number_joined++;
90    
91     chptr->number_joined -= (CurrentTime - chptr->last_join_time) *
92     (((float)GlobalSetOptions.joinfloodcount) /
93     (float)GlobalSetOptions.joinfloodtime);
94    
95     if (chptr->number_joined <= 0)
96     {
97     chptr->number_joined = 0;
98     ClearJoinFloodNoticed(chptr);
99     }
100     else if (chptr->number_joined >= GlobalSetOptions.joinfloodcount)
101     {
102     chptr->number_joined = GlobalSetOptions.joinfloodcount;
103    
104     if (!IsSetJoinFloodNoticed(chptr))
105     {
106     SetJoinFloodNoticed(chptr);
107     sendto_realops_flags(UMODE_BOTS, L_ALL,
108     "Possible Join Flooder %s on %s target: %s",
109     get_client_name(who, HIDE_IP),
110     who->servptr->name, chptr->chname);
111     }
112     }
113    
114     chptr->last_join_time = CurrentTime;
115     }
116    
117     ms = BlockHeapAlloc(member_heap);
118     ms->client_p = who;
119     ms->chptr = chptr;
120     ms->flags = flags;
121    
122     dlinkAdd(ms, &ms->channode, &chptr->members);
123    
124     if (MyConnect(who))
125     dlinkAdd(ms, &ms->locchannode, &chptr->locmembers);
126    
127     dlinkAdd(ms, &ms->usernode, &who->channel);
128     }
129    
130     /*! \brief deletes an user from a channel by removing a link in the
131     * channels member chain.
132     * \param member pointer to Membership struct
133     */
134     void
135     remove_user_from_channel(struct Membership *member)
136     {
137     struct Client *client_p = member->client_p;
138     struct Channel *chptr = member->chptr;
139    
140     dlinkDelete(&member->channode, &chptr->members);
141    
142     if (MyConnect(client_p))
143     dlinkDelete(&member->locchannode, &chptr->locmembers);
144    
145     dlinkDelete(&member->usernode, &client_p->channel);
146    
147     BlockHeapFree(member_heap, member);
148    
149     if (dlink_list_length(&chptr->members) == 0)
150     {
151     assert(dlink_list_length(&chptr->locmembers) == 0);
152     destroy_channel(chptr);
153     }
154     }
155    
156     /* send_members()
157     *
158     * inputs -
159     * output - NONE
160     * side effects -
161     */
162     static void
163     send_members(struct Client *client_p, struct Channel *chptr,
164     char *lmodebuf, char *lparabuf)
165     {
166     struct Membership *ms;
167     dlink_node *ptr;
168     int tlen; /* length of text to append */
169     char *t, *start; /* temp char pointer */
170    
171     start = t = buf + ircsprintf(buf, ":%s SJOIN %lu %s %s %s:",
172     ID_or_name(&me, client_p),
173     (unsigned long)chptr->channelts,
174     chptr->chname, lmodebuf, lparabuf);
175    
176     DLINK_FOREACH(ptr, chptr->members.head)
177     {
178     ms = ptr->data;
179    
180     tlen = strlen(IsCapable(client_p, CAP_TS6) ?
181     ID(ms->client_p) : ms->client_p->name) + 1; /* nick + space */
182    
183     if (ms->flags & CHFL_CHANOP)
184     tlen++;
185     #ifdef HALFOPS
186     if (ms->flags & CHFL_HALFOP)
187     tlen++;
188     #endif
189     if (ms->flags & CHFL_VOICE)
190     tlen++;
191    
192     /* space will be converted into CR, but we also need space for LF..
193     * That's why we use '- 1' here
194     * -adx */
195     if (t + tlen - buf > sizeof(buf) - 1)
196     {
197     *(t - 1) = '\0'; /* kill the space and terminate the string */
198     sendto_one(client_p, "%s", buf);
199     t = start;
200     }
201    
202     strcpy(t, get_member_status(ms, YES));
203     t += strlen(t);
204    
205     if (IsCapable(client_p, CAP_TS6))
206     strcpy(t, ID(ms->client_p));
207     else
208     strcpy(t, ms->client_p->name);
209     t += strlen(t);
210     *t++ = ' ';
211     }
212    
213     /* should always be non-NULL unless we have a kind of persistent channels */
214     if (chptr->members.head != NULL)
215     t--; /* take the space out */
216     *t = '\0';
217     sendto_one(client_p, "%s", buf);
218     }
219    
220     /*! \brief sends +b/+e/+I
221     * \param client_p client pointer to server
222     * \param chptr pointer to channel
223     * \param top pointer to top of mode link list to send
224     * \param flag char flag flagging type of mode. Currently this can be 'b', e' or 'I'
225     */
226     static void
227     send_mode_list(struct Client *client_p, struct Channel *chptr,
228     dlink_list *top, char flag)
229     {
230     int ts5 = !IsCapable(client_p, CAP_TS6);
231     dlink_node *lp;
232     struct Ban *banptr;
233     char pbuf[IRCD_BUFSIZE];
234     int tlen, mlen, cur_len, count = 0;
235     char *mp = NULL, *pp = pbuf;
236    
237     if (top == NULL || top->length == 0)
238     return;
239    
240     if (ts5)
241     mlen = ircsprintf(buf, ":%s MODE %s +", me.name, chptr->chname);
242     else
243     mlen = ircsprintf(buf, ":%s BMASK %lu %s %c :", me.id,
244     (unsigned long)chptr->channelts, chptr->chname, flag);
245    
246     /* MODE needs additional one byte for space between buf and pbuf */
247     cur_len = mlen + ts5;
248     mp = buf + mlen;
249    
250     DLINK_FOREACH(lp, top->head)
251     {
252     banptr = lp->data;
253    
254     /* must add another b/e/I letter if we use MODE */
255     tlen = banptr->len + 3 + ts5;
256    
257     /*
258     * send buffer and start over if we cannot fit another ban,
259     * or if the target is non-ts6 and we have too many modes in
260     * in this line.
261     */
262     if (cur_len + (tlen - 1) > IRCD_BUFSIZE - 2 ||
263     (!IsCapable(client_p, CAP_TS6) &&
264     (count >= MAXMODEPARAMS || pp - pbuf >= MODEBUFLEN)))
265     {
266     *(pp - 1) = '\0'; /* get rid of trailing space on buffer */
267     sendto_one(client_p, "%s%s%s", buf, ts5 ? " " : "", pbuf);
268    
269     cur_len = mlen + ts5;
270     mp = buf + mlen;
271     pp = pbuf;
272     count = 0;
273     }
274    
275     count++;
276     if (ts5)
277     {
278     *mp++ = flag;
279     *mp = '\0';
280     }
281    
282     pp += ircsprintf(pp, "%s!%s@%s ", banptr->name, banptr->username,
283     banptr->host);
284     cur_len += tlen;
285     }
286    
287     *(pp - 1) = '\0'; /* get rid of trailing space on buffer */
288     sendto_one(client_p, "%s%s%s", buf, ts5 ? " " : "", pbuf);
289     }
290    
291     /*! \brief send "client_p" a full list of the modes for channel chptr
292     * \param client_p pointer to client client_p
293     * \param chptr pointer to channel pointer
294     */
295     void
296     send_channel_modes(struct Client *client_p, struct Channel *chptr)
297     {
298     if (chptr->chname[0] != '#')
299     return;
300    
301     *modebuf = *parabuf = '\0';
302     channel_modes(chptr, client_p, modebuf, parabuf);
303     send_members(client_p, chptr, modebuf, parabuf);
304    
305     send_mode_list(client_p, chptr, &chptr->banlist, 'b');
306    
307     if (IsCapable(client_p, CAP_EX))
308     send_mode_list(client_p, chptr, &chptr->exceptlist, 'e');
309     if (IsCapable(client_p, CAP_IE))
310     send_mode_list(client_p, chptr, &chptr->invexlist, 'I');
311     }
312    
313     /*! \brief check channel name for invalid characters
314     * \param name pointer to channel name string
315     * \return TRUE (1) if name ok, FALSE (0) otherwise
316     */
317     int
318     check_channel_name(const char *name)
319     {
320     const unsigned char *p = (const unsigned char *)name;
321     assert(name != NULL);
322    
323     for (; *p; ++p)
324     if (!IsChanChar(*p))
325     return 0;
326    
327     return 1;
328     }
329    
330     void
331     remove_ban(struct Ban *bptr, dlink_list *list)
332     {
333     dlinkDelete(&bptr->node, list);
334    
335     MyFree(bptr->name);
336     MyFree(bptr->username);
337     MyFree(bptr->host);
338     MyFree(bptr->who);
339    
340     BlockHeapFree(ban_heap, bptr);
341     }
342    
343     /* free_channel_list()
344     *
345     * inputs - pointer to dlink_list
346     * output - NONE
347     * side effects -
348     */
349     void
350     free_channel_list(dlink_list *list)
351     {
352     dlink_node *ptr = NULL, *next_ptr = NULL;
353    
354     DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
355     remove_ban(ptr->data, list);
356    
357     assert(list->tail == NULL && list->head == NULL);
358     }
359    
360     /*! \brief Get Channel block for chname (and allocate a new channel
361     * block, if it didn't exist before)
362     * \param client_p client pointer
363     * \param chname channel name
364     * \param isnew pointer to int flag whether channel was newly created or not
365     * \return channel block or NULL if illegal name
366     */
367     struct Channel *
368     get_or_create_channel(struct Client *client_p, const char *chname, int *isnew)
369     {
370     struct Channel *chptr = NULL;
371     int len;
372    
373     if (EmptyString(chname))
374     return NULL;
375    
376     if ((len = strlen(chname)) > CHANNELLEN)
377     {
378     if (IsServer(client_p))
379     sendto_realops_flags(UMODE_DEBUG, L_ALL,
380     "*** Long channel name from %s (%d > %d): %s",
381     client_p->name, len, CHANNELLEN, chname);
382     return NULL;
383     }
384    
385     if ((chptr = hash_find_channel(chname)) != NULL)
386     {
387     if (isnew != NULL)
388     *isnew = 0;
389    
390     return chptr;
391     }
392    
393     if (isnew != NULL)
394     *isnew = 1;
395    
396     chptr = BlockHeapAlloc(channel_heap);
397     /* doesn't hurt to set it here */
398     chptr->channelts = chptr->last_join_time = CurrentTime;
399    
400     strlcpy(chptr->chname, chname, sizeof(chptr->chname));
401     dlinkAdd(chptr, &chptr->node, &global_channel_list);
402    
403     hash_add_channel(chptr);
404    
405     return chptr;
406     }
407    
408     /*! \brief walk through this channel, and destroy it.
409     * \param chptr channel pointer
410     */
411     void
412     destroy_channel(struct Channel *chptr)
413     {
414     dlink_node *ptr = NULL, *ptr_next = NULL;
415    
416     DLINK_FOREACH_SAFE(ptr, ptr_next, chptr->invites.head)
417     del_invite(chptr, ptr->data);
418    
419     /* free ban/exception/invex lists */
420     free_channel_list(&chptr->banlist);
421     free_channel_list(&chptr->exceptlist);
422     free_channel_list(&chptr->invexlist);
423    
424     /* Free the topic */
425     free_topic(chptr);
426    
427     dlinkDelete(&chptr->node, &global_channel_list);
428     hash_del_channel(chptr);
429    
430     if (ServerInfo.hub)
431     if ((ptr = dlinkFindDelete(&lazylink_channels, chptr)))
432     free_dlink_node(ptr);
433    
434     BlockHeapFree(channel_heap, chptr);
435     }
436    
437     /*!
438     * \param chptr pointer to channel
439     * \return string pointer "=" if public, "@" if secret else "*"
440     */
441     static const char *
442     channel_pub_or_secret(struct Channel *chptr)
443     {
444     if (SecretChannel(chptr))
445     return "@";
446     if (PrivateChannel(chptr))
447     return "*";
448     return "=";
449     }
450    
451     /*! \brief lists all names on given channel
452     * \param source_p pointer to client struct requesting names
453     * \param chptr pointer to channel block
454     * \param show_eon show ENDOFNAMES numeric or not
455     * (don't want it with /names with no params)
456     */
457     void
458     channel_member_names(struct Client *source_p, struct Channel *chptr,
459     int show_eon)
460     {
461     struct Client *target_p = NULL;
462     struct Membership *ms = NULL;
463     dlink_node *ptr = NULL;
464     char lbuf[IRCD_BUFSIZE + 1];
465     char *t = NULL, *start = NULL;
466     int tlen = 0;
467     int is_member = IsMember(source_p, chptr);
468    
469     if (PubChannel(chptr) || is_member)
470     {
471     t = lbuf + ircsprintf(lbuf, form_str(RPL_NAMREPLY),
472     me.name, source_p->name,
473     channel_pub_or_secret(chptr),
474     chptr->chname);
475     start = t;
476    
477     DLINK_FOREACH(ptr, chptr->members.head)
478     {
479     ms = ptr->data;
480     target_p = ms->client_p;
481    
482     if (IsInvisible(target_p) && !is_member)
483     continue;
484    
485     tlen = strlen(target_p->name) + 1; /* nick + space */
486    
487     if (ms->flags & (CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE))
488     ++tlen;
489     if (t + tlen - lbuf > IRCD_BUFSIZE)
490     {
491     *(t - 1) = '\0';
492     sendto_one(source_p, "%s", lbuf);
493     t = start;
494     }
495    
496     t += ircsprintf(t, "%s%s ", get_member_status(ms, NO),
497     target_p->name);
498     }
499    
500     if (tlen != 0)
501     {
502     *(t - 1) = '\0';
503     sendto_one(source_p, "%s", lbuf);
504     }
505     }
506    
507     if (show_eon)
508     sendto_one(source_p, form_str(RPL_ENDOFNAMES),
509     me.name, source_p->name, chptr->chname);
510     }
511    
512     /*! \brief adds client to invite list
513     * \param chptr pointer to channel block
514     * \param who pointer to client to add invite to
515     */
516     void
517     add_invite(struct Channel *chptr, struct Client *who)
518     {
519     del_invite(chptr, who);
520    
521     /*
522     * delete last link in chain if the list is max length
523     */
524     if (dlink_list_length(&who->invited) >=
525     ConfigChannel.max_chans_per_user)
526     del_invite(who->invited.tail->data, who);
527    
528     /* add client to channel invite list */
529     dlinkAdd(who, make_dlink_node(), &chptr->invites);
530    
531     /* add channel to the end of the client invite list */
532     dlinkAdd(chptr, make_dlink_node(), &who->invited);
533     }
534    
535     /*! \brief Delete Invite block from channel invite list
536     * and client invite list
537     * \param chptr pointer to Channel struct
538     * \param who pointer to client to remove invites from
539     */
540     void
541     del_invite(struct Channel *chptr, struct Client *who)
542     {
543     dlink_node *ptr = NULL;
544    
545     if ((ptr = dlinkFindDelete(&who->invited, chptr)))
546     free_dlink_node(ptr);
547    
548     if ((ptr = dlinkFindDelete(&chptr->invites, who)))
549     free_dlink_node(ptr);
550     }
551    
552     /* get_member_status()
553     *
554     * inputs - pointer to struct Membership
555     * - YES if we can combine different flags
556     * output - string either @, +, % or "" depending on whether
557     * chanop, voiced or user
558     * side effects -
559     *
560     * NOTE: Returned string is usually a static buffer
561     * (like in get_client_name)
562     */
563     const char *
564     get_member_status(const struct Membership *ms, int combine)
565     {
566     static char buffer[4];
567     char *p = NULL;
568    
569     if (ms == NULL)
570     return "";
571     p = buffer;
572    
573     if (ms->flags & CHFL_CHANOP)
574     {
575     if (!combine)
576     return "@";
577     *p++ = '@';
578     }
579    
580     #ifdef HALFOPS
581     if (ms->flags & CHFL_HALFOP)
582     {
583     if (!combine)
584     return "%";
585     *p++ = '%';
586     }
587     #endif
588    
589     if (ms->flags & CHFL_VOICE)
590     *p++ = '+';
591     *p = '\0';
592    
593     return buffer;
594     }
595    
596     /*!
597     * \param who pointer to Client to check
598     * \param list pointer to ban list to search
599     * \return 1 if ban found for given n!u\@h mask, 0 otherwise
600     *
601     */
602     static int
603     find_bmask(const struct Client *who, const dlink_list *const list)
604     {
605     const dlink_node *ptr = NULL;
606    
607     DLINK_FOREACH(ptr, list->head)
608     {
609     const struct Ban *bp = ptr->data;
610    
611     if (match(bp->name, who->name) &&
612     match(bp->username, who->username) &&
613     (match(bp->host, who->host) ||
614     match(bp->host, who->sockhost) ||
615     match_cidr(bp->host, who->sockhost)))
616     return 1;
617     }
618    
619     return 0;
620     }
621    
622     /*!
623     * \param chptr pointer to channel block
624     * \param who pointer to client to check access fo
625     * \return 0 if not banned, 1 otherwise
626     */
627     int
628     is_banned(struct Channel *chptr, struct Client *who)
629     {
630     assert(IsClient(who));
631    
632     return find_bmask(who, &chptr->banlist) && (!ConfigChannel.use_except ||
633     !find_bmask(who, &chptr->exceptlist));
634     }
635    
636     /*!
637     * \param source_p pointer to client attempting to join
638     * \param chptr pointer to channel
639     * \param key key sent by client attempting to join if present
640     * \return ERR_BANNEDFROMCHAN, ERR_INVITEONLYCHAN, ERR_CHANNELISFULL
641     * or 0 if allowed to join.
642     */
643     int
644     can_join(struct Client *source_p, struct Channel *chptr, const char *key)
645     {
646     if (find_bmask(source_p, &chptr->banlist))
647     if (!ConfigChannel.use_except || !find_bmask(source_p, &chptr->exceptlist))
648     return ERR_BANNEDFROMCHAN;
649    
650     if (chptr->mode.mode & MODE_INVITEONLY)
651     if (!dlinkFind(&source_p->invited, chptr))
652     if (!ConfigChannel.use_invex || !find_bmask(source_p, &chptr->invexlist))
653     return ERR_INVITEONLYCHAN;
654    
655     if (chptr->mode.key[0] && (EmptyString(key) || irccmp(chptr->mode.key, key)))
656     return ERR_BADCHANNELKEY;
657    
658     if (chptr->mode.limit && dlink_list_length(&chptr->members) >=
659     chptr->mode.limit)
660     return ERR_CHANNELISFULL;
661    
662     return 0;
663     }
664    
665     int
666     has_member_flags(struct Membership *ms, unsigned int flags)
667     {
668     if (ms != NULL)
669     return ms->flags & flags;
670     return 0;
671     }
672    
673     struct Membership *
674     find_channel_link(struct Client *client_p, struct Channel *chptr)
675     {
676     dlink_node *ptr = NULL;
677    
678     if (!IsClient(client_p))
679     return NULL;
680    
681     DLINK_FOREACH(ptr, client_p->channel.head)
682     if (((struct Membership *)ptr->data)->chptr == chptr)
683     return (struct Membership *)ptr->data;
684    
685     return NULL;
686     }
687    
688     /*!
689     * \param chptr pointer to Channel struct
690     * \param source_p pointer to Client struct
691     * \return CAN_SEND_OPV if op or voiced on channel\n
692     * CAN_SEND_NONOP if can send to channel but is not an op\n
693     * CAN_SEND_NO if they cannot send to channel\n
694     */
695     int
696     can_send(struct Channel *chptr, struct Client *source_p)
697     {
698     struct Membership *ms = NULL;
699    
700     if (IsServer(source_p))
701     return CAN_SEND_OPV;
702    
703     if (MyClient(source_p) && !IsExemptResv(source_p) &&
704     !(IsOper(source_p) && ConfigFileEntry.oper_pass_resv) &&
705     (!hash_find_resv(chptr->chname) == ConfigChannel.restrict_channels))
706     return CAN_SEND_NO;
707    
708     if ((ms = find_channel_link(source_p, chptr)) == NULL)
709     {
710     if (chptr->mode.mode & MODE_NOPRIVMSGS)
711     return CAN_SEND_NO;
712     }
713     else
714     {
715     if (ms->flags & (CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE))
716     return CAN_SEND_OPV;
717    
718     /* cache can send if quiet_on_ban and banned */
719     if (ConfigChannel.quiet_on_ban && MyClient(source_p))
720     {
721     if (ms->flags & CHFL_BAN_SILENCED)
722     return CAN_SEND_NO;
723    
724     if (!(ms->flags & CHFL_BAN_CHECKED))
725     {
726     if (is_banned(chptr, source_p))
727     {
728     ms->flags |= (CHFL_BAN_CHECKED|CHFL_BAN_SILENCED);
729     return CAN_SEND_NO;
730     }
731    
732     ms->flags |= CHFL_BAN_CHECKED;
733     }
734     }
735     }
736    
737     if (chptr->mode.mode & MODE_MODERATED)
738     return CAN_SEND_NO;
739    
740     return CAN_SEND_NONOP;
741     }
742    
743     /*! \brief Checks to see if given client can send a part message
744     * \param member pointer to channel membership
745     * \param chptr pointer to channel struct
746     * \param source_p pointer to struct Client to check
747     */
748     int
749     can_send_part(struct Membership *member, struct Channel *chptr,
750     struct Client *source_p)
751     {
752     if (has_member_flags(member, CHFL_CHANOP|CHFL_HALFOP))
753     return CAN_SEND_OPV;
754    
755     if (chptr->mode.mode & MODE_MODERATED)
756     return CAN_SEND_NO;
757    
758     if (ConfigChannel.quiet_on_ban && MyClient(source_p) &&
759     is_banned(chptr, source_p))
760     return CAN_SEND_NO;
761    
762     return CAN_SEND_NONOP;
763     }
764    
765     /*! \brief Updates the client's oper_warn_count_down, warns the
766     * IRC operators if necessary, and updates
767     * join_leave_countdown as needed.
768     * \param source_p pointer to struct Client to check
769     * \param name channel name or NULL if this is a part.
770     */
771     void
772     check_spambot_warning(struct Client *source_p, const char *name)
773     {
774     int t_delta = 0;
775     int decrement_count = 0;
776    
777     if ((GlobalSetOptions.spam_num &&
778     (source_p->localClient->join_leave_count >=
779     GlobalSetOptions.spam_num)))
780     {
781     if (source_p->localClient->oper_warn_count_down > 0)
782     source_p->localClient->oper_warn_count_down--;
783     else
784     source_p->localClient->oper_warn_count_down = 0;
785    
786     if (source_p->localClient->oper_warn_count_down == 0)
787     {
788     /* Its already known as a possible spambot */
789     if (name != NULL)
790     sendto_realops_flags(UMODE_BOTS, L_ALL,
791     "User %s (%s@%s) trying to join %s is a possible spambot",
792     source_p->name, source_p->username,
793     source_p->host, name);
794     else
795     sendto_realops_flags(UMODE_BOTS, L_ALL,
796     "User %s (%s@%s) is a possible spambot",
797     source_p->name, source_p->username,
798     source_p->host);
799     source_p->localClient->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
800     }
801     }
802     else
803     {
804     if ((t_delta = (CurrentTime - source_p->localClient->last_leave_time)) >
805     JOIN_LEAVE_COUNT_EXPIRE_TIME)
806     {
807     decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME);
808     if (decrement_count > source_p->localClient->join_leave_count)
809     source_p->localClient->join_leave_count = 0;
810     else
811     source_p->localClient->join_leave_count -= decrement_count;
812     }
813     else
814     {
815     if ((CurrentTime - (source_p->localClient->last_join_time)) <
816     GlobalSetOptions.spam_time)
817     {
818     /* oh, its a possible spambot */
819     source_p->localClient->join_leave_count++;
820     }
821     }
822    
823     if (name != NULL)
824     source_p->localClient->last_join_time = CurrentTime;
825     else
826     source_p->localClient->last_leave_time = CurrentTime;
827     }
828     }
829    
830     /*! \brief compares usercount and servercount against their split
831     * values and adjusts splitmode accordingly
832     * \param unused Unused address pointer
833     */
834     void
835     check_splitmode(void *unused)
836     {
837     if (splitchecking && (ConfigChannel.no_join_on_split ||
838     ConfigChannel.no_create_on_split))
839     {
840     const unsigned int server = dlink_list_length(&global_serv_list);
841    
842     if (!splitmode && ((server < split_servers) || (Count.total < split_users)))
843     {
844     splitmode = 1;
845    
846     sendto_realops_flags(UMODE_ALL,L_ALL,
847     "Network split, activating splitmode");
848     eventAddIsh("check_splitmode", check_splitmode, NULL, 10);
849     }
850     else if (splitmode && (server > split_servers) && (Count.total > split_users))
851     {
852     splitmode = 0;
853    
854     sendto_realops_flags(UMODE_ALL, L_ALL,
855     "Network rejoined, deactivating splitmode");
856     eventDelete(check_splitmode, NULL);
857     }
858     }
859     }
860    
861     /*! \brief Allocates a new topic
862     * \param chptr Channel to allocate a new topic for
863     */
864     static void
865     allocate_topic(struct Channel *chptr)
866     {
867     void *ptr = NULL;
868    
869     if (chptr == NULL)
870     return;
871    
872     ptr = BlockHeapAlloc(topic_heap);
873    
874     /* Basically we allocate one large block for the topic and
875     * the topic info. We then split it up into two and shove it
876     * in the chptr
877     */
878     chptr->topic = ptr;
879     chptr->topic_info = (char *)ptr + TOPICLEN+1;
880     *chptr->topic = '\0';
881     *chptr->topic_info = '\0';
882     }
883    
884     void
885     free_topic(struct Channel *chptr)
886     {
887     void *ptr = NULL;
888     assert(chptr);
889     if (chptr->topic == NULL)
890     return;
891    
892     /*
893     * If you change allocate_topic you MUST change this as well
894     */
895     ptr = chptr->topic;
896     BlockHeapFree(topic_heap, ptr);
897     chptr->topic = NULL;
898     chptr->topic_info = NULL;
899     }
900    
901     /*! \brief Sets the channel topic for chptr
902     * \param chptr Pointer to struct Channel
903     * \param topic The topic string
904     * \param topic_info n!u\@h formatted string of the topic setter
905     * \param topicts timestamp on the topic
906     */
907     void
908     set_channel_topic(struct Channel *chptr, const char *topic,
909     const char *topic_info, time_t topicts)
910     {
911     if (!EmptyString(topic))
912     {
913     if (chptr->topic == NULL)
914     allocate_topic(chptr);
915    
916     strlcpy(chptr->topic, topic, TOPICLEN+1);
917     strlcpy(chptr->topic_info, topic_info, USERHOST_REPLYLEN);
918     chptr->topic_time = topicts;
919     }
920     else
921     {
922     if (chptr->topic != NULL)
923     free_topic(chptr);
924    
925     chptr->topic_time = 0;
926     }
927     }
928    

Properties

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