ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel.c
Revision: 9365
Committed: Thu Apr 30 19:24:28 2020 UTC (3 years, 10 months ago) by michael
Content type: text/x-csrc
File size: 31728 byte(s)
Log Message:
- Fixed various style inconsistencies

File Contents

# User Rev Content
1 adx 30 /*
2 michael 2916 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 adx 30 *
4 michael 9101 * Copyright (c) 1997-2020 ircd-hybrid development team
5 adx 30 *
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 michael 4565 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 adx 30 * 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 michael 1011 #include "list.h"
29 adx 30 #include "channel.h"
30 michael 9265 #include "channel_invite.h"
31 adx 30 #include "channel_mode.h"
32     #include "client.h"
33     #include "hash.h"
34 michael 1632 #include "conf.h"
35 michael 7234 #include "conf_resv.h"
36 michael 371 #include "hostmask.h"
37 adx 30 #include "irc_string.h"
38     #include "ircd.h"
39     #include "numeric.h"
40 michael 3347 #include "server.h"
41 adx 30 #include "send.h"
42     #include "event.h"
43     #include "memory.h"
44 michael 3347 #include "misc.h"
45 michael 9234 #include "extban.h"
46 adx 30
47 michael 3235
48 michael 8439 /** Doubly linked list containing a list of all channels. */
49     static dlink_list channel_list;
50 adx 30
51    
52 michael 8439 /*! \brief Returns the channel_list as constant
53     * \return channel_list
54     */
55     const dlink_list *
56     channel_get_list(void)
57     {
58     return &channel_list;
59     }
60    
61 michael 3308 /*! \brief Adds a user to a channel by adding another link to the
62 adx 30 * channels member chain.
63 michael 9081 * \param channel Pointer to channel to add client to
64 michael 9250 * \param client Pointer to client (who) to add
65 michael 3308 * \param flags Flags for chanops etc
66     * \param flood_ctrl Whether to count this join in flood calculations
67 adx 30 */
68     void
69 michael 9250 add_user_to_channel(struct Channel *channel, struct Client *client,
70 michael 8664 unsigned int flags, bool flood_ctrl)
71 adx 30 {
72 michael 9250 assert(IsClient(client));
73 michael 5590
74 michael 7779 if (GlobalSetOptions.joinfloodtime)
75 adx 30 {
76 michael 8664 if (flood_ctrl == true)
77 michael 9081 ++channel->number_joined;
78 adx 30
79 michael 9081 channel->number_joined -= (event_base->time.sec_monotonic - channel->last_join_time) *
80 adx 30 (((float)GlobalSetOptions.joinfloodcount) /
81     (float)GlobalSetOptions.joinfloodtime);
82    
83 michael 9081 if (channel->number_joined <= 0)
84 adx 30 {
85 michael 9081 channel->number_joined = 0;
86     ClearJoinFloodNoticed(channel);
87 adx 30 }
88 michael 9081 else if (channel->number_joined >= GlobalSetOptions.joinfloodcount)
89 adx 30 {
90 michael 9081 channel->number_joined = GlobalSetOptions.joinfloodcount;
91 adx 30
92 michael 9081 if (!IsSetJoinFloodNoticed(channel))
93 adx 30 {
94 michael 9081 SetJoinFloodNoticed(channel);
95 michael 1618 sendto_realops_flags(UMODE_BOTS, L_ALL, SEND_NOTICE,
96 adx 30 "Possible Join Flooder %s on %s target: %s",
97 michael 9250 client_get_name(client, HIDE_IP),
98     client->servptr->name, channel->name);
99 adx 30 }
100     }
101    
102 michael 9081 channel->last_join_time = event_base->time.sec_monotonic;
103 adx 30 }
104    
105 michael 9081 struct ChannelMember *member = xcalloc(sizeof(*member));
106 michael 9250 member->client = client;
107 michael 9081 member->channel = channel;
108 michael 4815 member->flags = flags;
109 adx 30
110 michael 9081 dlinkAdd(member, &member->channode, &channel->members);
111 michael 4170
112 michael 9250 if (MyConnect(client))
113 michael 9081 dlinkAdd(member, &member->locchannode, &channel->members_local);
114 michael 4170
115 michael 9250 dlinkAdd(member, &member->usernode, &client->channel);
116 adx 30 }
117    
118 michael 3308 /*! \brief Deletes an user from a channel by removing a link in the
119 adx 30 * channels member chain.
120 michael 3308 * \param member Pointer to Membership struct
121 adx 30 */
122     void
123 michael 9081 remove_user_from_channel(struct ChannelMember *member)
124 adx 30 {
125 michael 9250 struct Client *const client = member->client;
126 michael 9081 struct Channel *const channel = member->channel;
127 adx 30
128 michael 9081 dlinkDelete(&member->channode, &channel->members);
129 michael 4170
130 michael 9250 if (MyConnect(client))
131 michael 9081 dlinkDelete(&member->locchannode, &channel->members_local);
132 michael 4170
133 michael 9250 dlinkDelete(&member->usernode, &client->channel);
134 adx 30
135 michael 8385 xfree(member);
136 adx 30
137 michael 9081 if (channel->members.head == NULL)
138     channel_free(channel);
139 adx 30 }
140    
141 michael 6373 /* channel_send_members()
142 adx 30 *
143     * inputs -
144     * output - NONE
145     * side effects -
146     */
147     static void
148 michael 9250 channel_send_members(struct Client *client, const struct Channel *channel,
149 michael 7797 const char *modebuf, const char *parabuf)
150 adx 30 {
151 michael 8059 dlink_node *node;
152 michael 9086 char buf[IRCD_BUFSIZE];
153 adx 30 int tlen; /* length of text to append */
154     char *t, *start; /* temp char pointer */
155    
156 michael 6782 start = t = buf + snprintf(buf, sizeof(buf), ":%s SJOIN %ju %s %s %s:",
157 michael 9081 me.id, channel->creation_time,
158     channel->name, modebuf, parabuf);
159 adx 30
160 michael 9081 DLINK_FOREACH(node, channel->members.head)
161 adx 30 {
162 michael 9081 const struct ChannelMember *member = node->data;
163 adx 30
164 michael 9081 tlen = strlen(member->client->id) + 1; /* +1 for space */
165 adx 30
166 michael 4815 if (member->flags & CHFL_CHANOP)
167 michael 3250 ++tlen;
168 michael 4815 if (member->flags & CHFL_HALFOP)
169 michael 3250 ++tlen;
170 michael 4815 if (member->flags & CHFL_VOICE)
171 michael 3250 ++tlen;
172 adx 30
173 michael 3250 /*
174     * Space will be converted into CR, but we also need space for LF..
175 michael 3782 * That's why we use '- 1' here -adx
176 michael 3250 */
177 michael 1330 if (t + tlen - buf > IRCD_BUFSIZE - 1)
178 adx 30 {
179 michael 3250 *(t - 1) = '\0'; /* Kill the space and terminate the string */
180 michael 9250 sendto_one(client, "%s", buf);
181 adx 30 t = start;
182     }
183    
184 michael 4815 if (member->flags & CHFL_CHANOP)
185 michael 3140 *t++ = '@';
186 michael 4815 if (member->flags & CHFL_HALFOP)
187 michael 3140 *t++ = '%';
188 michael 4815 if (member->flags & CHFL_VOICE)
189 adx 356 *t++ = '+';
190 adx 30
191 michael 9081 strcpy(t, member->client->id);
192 michael 3135
193 adx 30 t += strlen(t);
194     *t++ = ' ';
195     }
196    
197 michael 3250 /* Should always be non-NULL unless we have a kind of persistent channels */
198 michael 9081 if (channel->members.head)
199 michael 8431 --t; /* Take the space out */
200 adx 30 *t = '\0';
201 michael 9250 sendto_one(client, "%s", buf);
202 adx 30 }
203    
204 michael 3308 /*! \brief Sends +b/+e/+I
205 michael 9250 * \param client Client pointer to server
206 michael 9081 * \param channel Pointer to channel
207 michael 3997 * \param list Pointer to list of modes to send
208 michael 3308 * \param flag Char flag flagging type of mode. Currently this can be 'b', e' or 'I'
209 adx 30 */
210     static void
211 michael 9250 channel_send_mask_list(struct Client *client, const struct Channel *channel,
212 michael 6373 const dlink_list *list, const char flag)
213 adx 30 {
214 michael 7687 dlink_node *node;
215 michael 9086 char mbuf[IRCD_BUFSIZE];
216     char pbuf[IRCD_BUFSIZE];
217 michael 9348 size_t tlen, mlen, cur_len;
218 michael 3144 char *pp = pbuf;
219 adx 30
220 michael 8447 if (dlink_list_length(list) == 0)
221 adx 30 return;
222    
223 michael 6782 mlen = snprintf(mbuf, sizeof(mbuf), ":%s BMASK %ju %s %c :", me.id,
224 michael 9081 channel->creation_time, channel->name, flag);
225 michael 3135 cur_len = mlen;
226 adx 30
227 michael 4800 DLINK_FOREACH(node, list->head)
228 adx 30 {
229 michael 4815 const struct Ban *ban = node->data;
230 adx 30
231 michael 9234 tlen = ban->banstr_len + 1; /* +1 for space */
232 adx 30
233     /*
234 michael 3996 * Send buffer and start over if we cannot fit another ban
235 adx 30 */
236 michael 9348 if (cur_len + (tlen - 1) > sizeof(pbuf) - 2)
237 adx 30 {
238 michael 3250 *(pp - 1) = '\0'; /* Get rid of trailing space on buffer */
239 michael 9250 sendto_one(client, "%s%s", mbuf, pbuf);
240 adx 30
241 michael 3135 cur_len = mlen;
242 adx 30 pp = pbuf;
243     }
244    
245 michael 9348 pp += snprintf(pp, sizeof(pbuf) - (pp - pbuf), "%s ", ban->banstr);
246 adx 30 cur_len += tlen;
247     }
248    
249 michael 3250 *(pp - 1) = '\0'; /* Get rid of trailing space on buffer */
250 michael 9250 sendto_one(client, "%s%s", mbuf, pbuf);
251 adx 30 }
252    
253 michael 9250 /*! \brief Send "client" a full list of the modes for channel channel
254     * \param client Pointer to client client
255     * \param channel Pointer to channel pointer
256 adx 30 */
257     void
258 michael 9250 channel_send_modes(struct Client *client, const struct Channel *channel)
259 adx 30 {
260 michael 3145 char modebuf[MODEBUFLEN] = "";
261     char parabuf[MODEBUFLEN] = "";
262    
263 michael 9250 channel_modes(channel, client, modebuf, parabuf);
264     channel_send_members(client, channel, modebuf, parabuf);
265 adx 30
266 michael 9250 channel_send_mask_list(client, channel, &channel->banlist, 'b');
267     channel_send_mask_list(client, channel, &channel->exceptlist, 'e');
268     channel_send_mask_list(client, channel, &channel->invexlist, 'I');
269 adx 30 }
270    
271 michael 3308 /*! \brief Check channel name for invalid characters
272     * \param name Pointer to channel name string
273     * \param local Indicates whether it's a local or remote creation
274 michael 632 * \return 0 if invalid, 1 otherwise
275 adx 30 */
276 michael 8660 bool
277     channel_check_name(const char *name, bool local)
278 adx 30 {
279 michael 632 const char *p = name;
280 michael 3421
281 michael 5590 assert(!EmptyString(p));
282 adx 30
283 michael 632 if (!IsChanPrefix(*p))
284 michael 8660 return false;
285 adx 30
286 michael 8660 if (local == false || ConfigChannel.disable_fake_channels == 0)
287 michael 632 {
288     while (*++p)
289 db 634 if (!IsChanChar(*p))
290 michael 8660 return false;
291 michael 632 }
292     else
293     {
294     while (*++p)
295 db 634 if (!IsVisibleChanChar(*p))
296 michael 8660 return false;
297 michael 632 }
298    
299 michael 3421 return p - name <= CHANNELLEN;
300 adx 30 }
301    
302     void
303 michael 4815 remove_ban(struct Ban *ban, dlink_list *list)
304 adx 30 {
305 michael 4815 dlinkDelete(&ban->node, list);
306 michael 8385 xfree(ban);
307 adx 30 }
308    
309 michael 6373 /* channel_free_mask_list()
310 adx 30 *
311     * inputs - pointer to dlink_list
312     * output - NONE
313     * side effects -
314     */
315 michael 6373 static void
316     channel_free_mask_list(dlink_list *list)
317 adx 30 {
318 michael 7266 while (list->head)
319     {
320     struct Ban *ban = list->head->data;
321     remove_ban(ban, list);
322     }
323 adx 30 }
324    
325 michael 4618 /*! \brief Get Channel block for name (and allocate a new channel
326 adx 30 * block, if it didn't exist before)
327 michael 4618 * \param name Channel name
328 michael 3308 * \return Channel block
329 adx 30 */
330     struct Channel *
331 michael 6373 channel_make(const char *name)
332 adx 30 {
333 michael 4618 assert(!EmptyString(name));
334 adx 30
335 michael 9081 struct Channel *channel = xcalloc(sizeof(*channel));
336     channel->hnextch = channel;
337 michael 3308 /* Doesn't hurt to set it here */
338 michael 9081 channel->creation_time = event_base->time.sec_real;
339     channel->last_join_time = event_base->time.sec_monotonic;
340 adx 30
341 michael 8027 /* Cache channel name length to avoid repetitive strlen() calls. */
342 michael 9081 channel->name_len = strlcpy(channel->name, name, sizeof(channel->name));
343     if (channel->name_len >= sizeof(channel->name))
344     channel->name_len = sizeof(channel->name) - 1;
345 michael 6990
346 michael 9081 dlinkAdd(channel, &channel->node, &channel_list);
347     hash_add_channel(channel);
348 adx 30
349 michael 9081 return channel;
350 adx 30 }
351    
352 michael 3308 /*! \brief Walk through this channel, and destroy it.
353 michael 9081 * \param channel Channel pointer
354 adx 30 */
355     void
356 michael 9081 channel_free(struct Channel *channel)
357 adx 30 {
358 michael 9265 invite_clear_list(&channel->invites);
359 adx 30
360 michael 3308 /* Free ban/exception/invex lists */
361 michael 9081 channel_free_mask_list(&channel->banlist);
362     channel_free_mask_list(&channel->exceptlist);
363     channel_free_mask_list(&channel->invexlist);
364 adx 30
365 michael 9081 dlinkDelete(&channel->node, &channel_list);
366     hash_del_channel(channel);
367 adx 30
368 michael 9081 assert(channel->hnextch == channel);
369 michael 8588
370 michael 9081 assert(channel->node.prev == NULL);
371     assert(channel->node.next == NULL);
372 michael 8588
373 michael 9081 assert(dlink_list_length(&channel->members_local) == 0);
374     assert(channel->members_local.head == NULL);
375     assert(channel->members_local.tail == NULL);
376 michael 8588
377 michael 9081 assert(dlink_list_length(&channel->members) == 0);
378     assert(channel->members.head == NULL);
379     assert(channel->members.tail == NULL);
380 michael 8588
381 michael 9081 assert(dlink_list_length(&channel->invites) == 0);
382     assert(channel->invites.head == NULL);
383     assert(channel->invites.tail == NULL);
384 michael 8588
385 michael 9081 assert(dlink_list_length(&channel->banlist) == 0);
386     assert(channel->banlist.head == NULL);
387     assert(channel->banlist.tail == NULL);
388 michael 8588
389 michael 9081 assert(dlink_list_length(&channel->exceptlist) == 0);
390     assert(channel->exceptlist.head == NULL);
391     assert(channel->exceptlist.tail == NULL);
392 michael 8588
393 michael 9081 assert(dlink_list_length(&channel->invexlist) == 0);
394     assert(channel->invexlist.head == NULL);
395     assert(channel->invexlist.tail == NULL);
396 michael 8588
397 michael 9081 xfree(channel);
398 adx 30 }
399    
400     /*!
401 michael 9081 * \param channel Pointer to channel
402 michael 3308 * \return String pointer "=" if public, "@" if secret else "*"
403 adx 30 */
404     static const char *
405 michael 9081 channel_pub_or_secret(const struct Channel *channel)
406 adx 30 {
407 michael 9081 if (SecretChannel(channel))
408 adx 30 return "@";
409 michael 9081 if (PrivateChannel(channel))
410 adx 30 return "*";
411     return "=";
412     }
413    
414     /*! \brief lists all names on given channel
415 michael 9250 * \param client Pointer to client struct requesting names
416 michael 9081 * \param channel Pointer to channel block
417 michael 3308 * \param show_eon Show RPL_ENDOFNAMES numeric or not
418 adx 30 * (don't want it with /names with no params)
419     */
420     void
421 michael 9250 channel_member_names(struct Client *client, struct Channel *channel, bool show_eon)
422 adx 30 {
423 michael 7687 dlink_node *node;
424 michael 9086 char buf[IRCD_BUFSIZE + 1];
425 adx 30 int tlen = 0;
426 michael 9250 bool is_member = IsMember(client, channel);
427     bool multi_prefix = HasCap(client, CAP_MULTI_PREFIX) != 0;
428     bool uhnames = HasCap(client, CAP_UHNAMES) != 0;
429 adx 30
430 michael 9250 assert(IsClient(client));
431 michael 5590
432 michael 9081 if (PubChannel(channel) || is_member == true)
433 adx 30 {
434 michael 9250 char *t = buf + snprintf(buf, sizeof(buf), numeric_form(RPL_NAMREPLY), me.name, client->name,
435 michael 9086 channel_pub_or_secret(channel), channel->name);
436     char *start = t;
437 adx 30
438 michael 9081 DLINK_FOREACH(node, channel->members.head)
439 adx 30 {
440 michael 9081 const struct ChannelMember *member = node->data;
441 adx 30
442 michael 9081 if (HasUMode(member->client, UMODE_INVISIBLE) && is_member == false)
443 adx 30 continue;
444    
445 michael 8656 if (uhnames == true)
446 michael 9081 tlen = strlen(member->client->name) + strlen(member->client->username) +
447     strlen(member->client->host) + 3; /* +3 for ! + @ + space */
448 michael 8431 else
449 michael 9081 tlen = strlen(member->client->name) + 1; /* +1 for space */
450 adx 30
451 michael 8656 if (multi_prefix == true)
452 michael 506 {
453 michael 4815 if (member->flags & CHFL_CHANOP)
454 michael 506 ++tlen;
455 michael 4815 if (member->flags & CHFL_HALFOP)
456 michael 506 ++tlen;
457 michael 4815 if (member->flags & CHFL_VOICE)
458 michael 506 ++tlen;
459     }
460 michael 8431 else
461     {
462     if (member->flags & (CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE))
463     ++tlen;
464     }
465 michael 506
466 michael 4388 if (t + tlen - buf > IRCD_BUFSIZE - 2)
467 adx 30 {
468     *(t - 1) = '\0';
469 michael 9250 sendto_one(client, "%s", buf);
470 adx 30 t = start;
471     }
472    
473 michael 8656 if (uhnames == true)
474 michael 4815 t += sprintf(t, "%s%s!%s@%s ", get_member_status(member, multi_prefix),
475 michael 9081 member->client->name, member->client->username,
476     member->client->host);
477 michael 8431 else
478     t += sprintf(t, "%s%s ", get_member_status(member, multi_prefix),
479 michael 9081 member->client->name);
480 adx 30 }
481    
482 michael 3215 if (tlen)
483 adx 30 {
484     *(t - 1) = '\0';
485 michael 9250 sendto_one(client, "%s", buf);
486 adx 30 }
487     }
488    
489 michael 8656 if (show_eon == true)
490 michael 9250 sendto_one_numeric(client, &me, RPL_ENDOFNAMES, channel->name);
491 adx 30 }
492    
493     /* get_member_status()
494     *
495 michael 9081 * inputs - pointer to struct ChannelMember
496 adx 30 * - YES if we can combine different flags
497     * output - string either @, +, % or "" depending on whether
498     * chanop, voiced or user
499     * side effects -
500     *
501     * NOTE: Returned string is usually a static buffer
502 michael 7997 * (like in client_get_name)
503 adx 30 */
504     const char *
505 michael 9081 get_member_status(const struct ChannelMember *member, bool combine)
506 adx 30 {
507 michael 6904 static char buffer[CMEMBER_STATUS_FLAGS_LEN + 1]; /* +1 for \0 */
508 michael 1902 char *p = buffer;
509 adx 30
510 michael 4815 if (member->flags & CHFL_CHANOP)
511 adx 30 {
512 michael 8656 if (combine == false)
513 adx 30 return "@";
514     *p++ = '@';
515     }
516    
517 michael 4815 if (member->flags & CHFL_HALFOP)
518 adx 30 {
519 michael 8656 if (combine == false)
520 adx 30 return "%";
521     *p++ = '%';
522     }
523    
524 michael 4815 if (member->flags & CHFL_VOICE)
525 adx 30 *p++ = '+';
526     *p = '\0';
527    
528     return buffer;
529     }
530    
531     /*!
532 michael 9250 * \param client Pointer to Client to check
533     * \param list Pointer to ban list to search
534 adx 30 * \return 1 if ban found for given n!u\@h mask, 0 otherwise
535     */
536 michael 8664 static bool
537 michael 9250 ban_matches(struct Client *client, struct Channel *channel, struct Ban *ban)
538 adx 30 {
539 michael 9234 /* Is a matching extban, call custom match handler */
540     if (ban->extban & extban_matching_mask())
541     {
542     struct Extban *extban = extban_find_flag(ban->extban & extban_matching_mask());
543     if (extban == NULL)
544     return false;
545    
546 michael 9250 if (extban->matches == NULL || extban->matches(client, channel, ban) == EXTBAN_NO_MATCH)
547 michael 9234 return false;
548    
549     return true;
550     }
551    
552 michael 9250 if (match(ban->name, client->name) == 0 && match(ban->user, client->username) == 0)
553 michael 9234 {
554     switch (ban->type)
555     {
556     case HM_HOST:
557 michael 9250 if (match(ban->host, client->realhost) == 0 ||
558     match(ban->host, client->sockhost) == 0 || match(ban->host, client->host) == 0)
559 michael 9234 return true;
560     break;
561     case HM_IPV4:
562 michael 9250 if (client->ip.ss.ss_family == AF_INET)
563     if (match_ipv4(&client->ip, &ban->addr, ban->bits))
564 michael 9234 return true;
565     break;
566     case HM_IPV6:
567 michael 9250 if (client->ip.ss.ss_family == AF_INET6)
568     if (match_ipv6(&client->ip, &ban->addr, ban->bits))
569 michael 9234 return true;
570     break;
571     default:
572     assert(0);
573     }
574     }
575    
576     return false;
577     }
578    
579     bool
580 michael 9250 find_bmask(struct Client *client, struct Channel *channel, const dlink_list *list, struct Extban *extban)
581 michael 9234 {
582 michael 7687 dlink_node *node;
583 adx 30
584 michael 4800 DLINK_FOREACH(node, list->head)
585 adx 30 {
586 michael 9234 struct Ban *ban = node->data;
587 adx 30
588 michael 9234 /* Looking for a specific type of extban? */
589     if (extban)
590 michael 371 {
591 michael 9234 if (!(ban->extban & extban->flag))
592     continue;
593 michael 371 }
594 michael 9234 else
595     {
596     /*
597     * Acting extbans have their own time they act and are not general purpose bans,
598     * so skip them unless we are hunting them.
599     */
600     if (ban->extban & extban_acting_mask())
601     continue;
602     }
603    
604 michael 9250 bool matches = ban_matches(client, channel, ban);
605 michael 9234 if (matches == false)
606     continue;
607    
608     return true;
609 adx 30 }
610    
611 michael 8664 return false;
612 adx 30 }
613    
614     /*!
615 michael 9250 * \param channel Pointer to channel block
616     * \param client Pointer to client to check access fo
617 adx 30 * \return 0 if not banned, 1 otherwise
618     */
619 michael 8664 bool
620 michael 9250 is_banned(struct Channel *channel, struct Client *client)
621 adx 30 {
622 michael 9250 if (find_bmask(client, channel, &channel->banlist, NULL) == true)
623     return find_bmask(client, channel, &channel->exceptlist, NULL) == false;
624 michael 8664 return false;
625 adx 30 }
626    
627 michael 3308 /*! Tests if a client can join a certain channel
628 michael 9250 * \param client Pointer to client attempting to join
629 michael 9081 * \param channel Pointer to channel
630 michael 3308 * \param key Key sent by client attempting to join if present
631 adx 30 * \return ERR_BANNEDFROMCHAN, ERR_INVITEONLYCHAN, ERR_CHANNELISFULL
632     * or 0 if allowed to join.
633     */
634 michael 6881 static int
635 michael 9250 can_join(struct Client *client, struct Channel *channel, const char *key)
636 adx 30 {
637 michael 9250 if (HasCMode(channel, MODE_SECUREONLY) && !HasUMode(client, UMODE_SECURE))
638 michael 9157 return ERR_SECUREONLYCHAN;
639 michael 1150
640 michael 9250 if (HasCMode(channel, MODE_REGONLY) && !HasUMode(client, UMODE_REGISTERED))
641 michael 1173 return ERR_NEEDREGGEDNICK;
642    
643 michael 9250 if (HasCMode(channel, MODE_OPERONLY) && !HasUMode(client, UMODE_OPER))
644 michael 1150 return ERR_OPERONLYCHAN;
645    
646 michael 9081 if (HasCMode(channel, MODE_INVITEONLY))
647 michael 9265 if (invite_find(channel, client) == NULL)
648 michael 9250 if (find_bmask(client, channel, &channel->invexlist, NULL) == false)
649 adx 30 return ERR_INVITEONLYCHAN;
650    
651 michael 9081 if (channel->mode.key[0] && (key == NULL || strcmp(channel->mode.key, key)))
652 adx 30 return ERR_BADCHANNELKEY;
653    
654 michael 9081 if (channel->mode.limit && dlink_list_length(&channel->members) >=
655     channel->mode.limit)
656 adx 30 return ERR_CHANNELISFULL;
657    
658 michael 9250 if (is_banned(channel, client) == true)
659 michael 2208 return ERR_BANNEDFROMCHAN;
660    
661 michael 9250 return extban_join_can_join(channel, client, NULL);
662 adx 30 }
663    
664     int
665 michael 9081 has_member_flags(const struct ChannelMember *member, const unsigned int flags)
666 adx 30 {
667 michael 4815 return member && (member->flags & flags);
668 adx 30 }
669    
670 michael 9081 struct ChannelMember *
671 michael 9250 find_channel_link(const struct Client *client, const struct Channel *channel)
672 adx 30 {
673 michael 7914 dlink_node *node;
674 adx 30
675 michael 9250 if (!IsClient(client))
676 adx 30 return NULL;
677    
678 michael 8439 /* Take the shortest of the two lists */
679 michael 9250 if (dlink_list_length(&channel->members) < dlink_list_length(&client->channel))
680 michael 2567 {
681 michael 9081 DLINK_FOREACH(node, channel->members.head)
682 michael 9250 if (((struct ChannelMember *)node->data)->client == client)
683 michael 4800 return node->data;
684 michael 2567 }
685     else
686     {
687 michael 9250 DLINK_FOREACH(node, client->channel.head)
688 michael 9081 if (((struct ChannelMember *)node->data)->channel == channel)
689 michael 4800 return node->data;
690 michael 2567 }
691 adx 30
692     return NULL;
693     }
694    
695 michael 4783 /*! Checks if a message contains control codes
696 michael 3888 * \param message The actual message string the client wants to send
697     * \return 1 if the message does contain any control codes, 0 otherwise
698 michael 1937 */
699 michael 8658 static bool
700 michael 1937 msg_has_ctrls(const char *message)
701     {
702 michael 9356 const unsigned char *p = (const unsigned char *)message;
703    
704     for (; *p; ++p)
705 michael 1937 {
706     if (*p > 31 || *p == 1)
707 michael 3952 continue; /* No control code or CTCP */
708 michael 1937
709 michael 3888 if (*p == 27) /* Escape */
710 michael 1937 {
711 michael 3888 /* ISO 2022 charset shift sequence */
712 michael 1937 if (*(p + 1) == '$' ||
713     *(p + 1) == '(')
714     {
715     ++p;
716     continue;
717     }
718     }
719    
720 michael 8658 return true; /* Control code */
721 michael 1937 }
722    
723 michael 8658 return false; /* No control code found */
724 michael 1937 }
725    
726 michael 3308 /*! Tests if a client can send to a channel
727 michael 9250 * \param channel Pointer to Channel struct
728     * \param client Pointer to Client struct
729     * \param member Pointer to Membership struct (can be NULL)
730     * \param message The actual message string the client wants to send
731 adx 30 * \return CAN_SEND_OPV if op or voiced on channel\n
732     * CAN_SEND_NONOP if can send to channel but is not an op\n
733 michael 1173 * ERR_CANNOTSENDTOCHAN or ERR_NEEDREGGEDNICK if they cannot send to channel\n
734 adx 30 */
735     int
736 michael 9250 can_send(struct Channel *channel, struct Client *client,
737 michael 9081 struct ChannelMember *member, const char *message, bool notice)
738 adx 30 {
739 michael 9086 const struct ResvItem *resv;
740 michael 1858
741 michael 9250 if (IsServer(client) || HasFlag(client, FLAGS_SERVICE))
742 adx 30 return CAN_SEND_OPV;
743    
744 michael 9250 if (MyConnect(client) && !HasFlag(client, FLAGS_EXEMPTRESV))
745     if (!(HasUMode(client, UMODE_OPER) && HasOFlag(client, OPER_FLAG_JOIN_RESV)))
746     if ((resv = resv_find(channel->name, match)) && resv_exempt_find(client, resv) == false)
747 michael 1834 return ERR_CANNOTSENDTOCHAN;
748 adx 30
749 michael 9081 if (HasCMode(channel, MODE_NOCTRL) && msg_has_ctrls(message) == true)
750 michael 1944 return ERR_NOCTRLSONCHAN;
751 michael 4884
752 michael 9081 if (HasCMode(channel, MODE_NOCTCP))
753 michael 5465 if (*message == '\001' && strncmp(message + 1, "ACTION ", 7))
754 michael 5464 return ERR_NOCTCP;
755    
756 michael 9250 if (member || (member = find_channel_link(client, channel)))
757 michael 5583 if (member->flags & (CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE))
758 adx 30 return CAN_SEND_OPV;
759 michael 4884
760 michael 9081 if (member == NULL && HasCMode(channel, MODE_NOPRIVMSGS))
761 michael 2441 return ERR_CANNOTSENDTOCHAN;
762 michael 4884
763 michael 9081 if (HasCMode(channel, MODE_MODERATED))
764 michael 1944 return ERR_CANNOTSENDTOCHAN;
765 michael 4884
766 michael 9250 if (HasCMode(channel, MODE_MODREG) && !HasUMode(client, UMODE_REGISTERED))
767 michael 1944 return ERR_NEEDREGGEDNICK;
768 adx 30
769 michael 9081 if (HasCMode(channel, MODE_NONOTICE) && notice == true)
770 michael 6858 return ERR_CANNOTSENDTOCHAN;
771    
772 michael 3308 /* Cache can send if banned */
773 michael 9250 if (MyConnect(client))
774 michael 1944 {
775 michael 4815 if (member)
776 adx 30 {
777 michael 4815 if (member->flags & CHFL_BAN_SILENCED)
778 michael 1834 return ERR_CANNOTSENDTOCHAN;
779 adx 30
780 michael 4815 if (!(member->flags & CHFL_BAN_CHECKED))
781 adx 30 {
782 michael 9250 if (is_banned(channel, client) == true)
783 adx 30 {
784 michael 5583 member->flags |= (CHFL_BAN_CHECKED | CHFL_BAN_SILENCED);
785 michael 1834 return ERR_CANNOTSENDTOCHAN;
786 adx 30 }
787    
788 michael 4815 member->flags |= CHFL_BAN_CHECKED;
789 adx 30 }
790     }
791 michael 9250 else if (is_banned(channel, client) == true)
792 michael 1941 return ERR_CANNOTSENDTOCHAN;
793     }
794 adx 30
795 michael 9250 return extban_mute_can_send(channel, client, member);
796 adx 30 }
797    
798     /*! \brief Updates the client's oper_warn_count_down, warns the
799     * IRC operators if necessary, and updates
800     * join_leave_countdown as needed.
801 michael 9250 * \param client Pointer to struct Client to check
802     * \param name Channel name or NULL if this is a part.
803 adx 30 */
804     void
805 michael 9250 check_spambot_warning(struct Client *client, const char *name)
806 adx 30 {
807 michael 8274 if (GlobalSetOptions.spam_num &&
808 michael 9250 (client->connection->join_leave_count >= GlobalSetOptions.spam_num))
809 adx 30 {
810 michael 9250 if (client->connection->oper_warn_count_down)
811     --client->connection->oper_warn_count_down;
812 adx 30
813 michael 9250 if (client->connection->oper_warn_count_down == 0)
814 adx 30 {
815 michael 3308 /* It's already known as a possible spambot */
816 michael 3235 if (name)
817 michael 1618 sendto_realops_flags(UMODE_BOTS, L_ALL, SEND_NOTICE,
818 adx 30 "User %s (%s@%s) trying to join %s is a possible spambot",
819 michael 9250 client->name, client->username,
820     client->host, name);
821 adx 30 else
822 michael 1618 sendto_realops_flags(UMODE_BOTS, L_ALL, SEND_NOTICE,
823 adx 30 "User %s (%s@%s) is a possible spambot",
824 michael 9250 client->name, client->username,
825     client->host);
826     client->connection->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
827 adx 30 }
828     }
829     else
830     {
831 michael 9250 unsigned int t_delta = event_base->time.sec_monotonic - client->connection->last_leave_time;
832 michael 8276 if (t_delta > JOIN_LEAVE_COUNT_EXPIRE_TIME)
833 adx 30 {
834 michael 8796 unsigned int decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME);
835 michael 9250 if (decrement_count > client->connection->join_leave_count)
836     client->connection->join_leave_count = 0;
837 adx 30 else
838 michael 9250 client->connection->join_leave_count -= decrement_count;
839 adx 30 }
840     else
841     {
842 michael 9250 if ((event_base->time.sec_monotonic - client->connection->last_join_time) < GlobalSetOptions.spam_time)
843     ++client->connection->join_leave_count; /* It's a possible spambot */
844 adx 30 }
845    
846 michael 3215 if (name)
847 michael 9250 client->connection->last_join_time = event_base->time.sec_monotonic;
848 adx 30 else
849 michael 9250 client->connection->last_leave_time = event_base->time.sec_monotonic;
850 adx 30 }
851     }
852    
853 michael 3308 /*! \brief Sets the channel topic for a certain channel
854 michael 9081 * \param channel Pointer to struct Channel
855 adx 30 * \param topic The topic string
856     * \param topic_info n!u\@h formatted string of the topic setter
857 michael 3308 * \param topicts Timestamp on the topic
858     * \param local Whether the topic is set by a local client
859 adx 30 */
860     void
861 michael 9081 channel_set_topic(struct Channel *channel, const char *topic,
862 michael 8660 const char *topic_info, uintmax_t topicts, bool local)
863 adx 30 {
864 michael 8660 if (local == true)
865 michael 9081 strlcpy(channel->topic, topic, IRCD_MIN(sizeof(channel->topic), ConfigServerInfo.max_topic_length + 1));
866 michael 1751 else
867 michael 9081 strlcpy(channel->topic, topic, sizeof(channel->topic));
868 michael 1751
869 michael 9081 strlcpy(channel->topic_info, topic_info, sizeof(channel->topic_info));
870     channel->topic_time = topicts;
871 adx 30 }
872 michael 3912
873     void
874 michael 9250 channel_do_join(struct Client *client, char *chan_list, char *key_list)
875 michael 3912 {
876     char *p = NULL;
877 michael 7282 const struct ResvItem *resv = NULL;
878 michael 9250 const struct ClassItem *const class = class_get_ptr(&client->connection->confs);
879 michael 3912 unsigned int flags = 0;
880    
881 michael 9250 assert(MyClient(client));
882 michael 5590
883 michael 7908 for (const char *name = strtok_r(chan_list, ",", &p); name;
884     name = strtok_r(NULL, ",", &p))
885 michael 3912 {
886     const char *key = NULL;
887    
888     /* If we have any more keys, take the first for this channel. */
889     if (!EmptyString(key_list) && (key_list = strchr(key = key_list, ',')))
890     *key_list++ = '\0';
891    
892     /* Empty keys are the same as no keys. */
893     if (key && *key == '\0')
894     key = NULL;
895    
896 michael 8660 if (channel_check_name(name, true) == false)
897 michael 3912 {
898 michael 9250 sendto_one_numeric(client, &me, ERR_BADCHANNAME, name);
899 michael 3912 continue;
900     }
901    
902 michael 9250 if (!HasFlag(client, FLAGS_EXEMPTRESV) &&
903     !(HasUMode(client, UMODE_OPER) && HasOFlag(client, OPER_FLAG_JOIN_RESV)) &&
904     ((resv = resv_find(name, match)) && resv_exempt_find(client, resv) == false))
905 michael 3912 {
906 michael 9250 sendto_one_numeric(client, &me, ERR_CHANBANREASON, name, resv->reason);
907 michael 4151 sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE,
908 michael 3912 "Forbidding reserved channel %s from user %s",
909 michael 9250 name, client_get_name(client, HIDE_IP));
910 michael 3912 continue;
911     }
912    
913 michael 9250 if (dlink_list_length(&client->channel) >=
914 michael 3933 ((class->max_channels) ? class->max_channels : ConfigChannel.max_channels))
915 michael 3912 {
916 michael 9250 sendto_one_numeric(client, &me, ERR_TOOMANYCHANNELS, name);
917 michael 3912 break;
918     }
919    
920 michael 9200 struct Channel *channel = hash_find_channel(name);
921     if (channel)
922 michael 3912 {
923 michael 9250 if (IsMember(client, channel))
924 michael 3912 continue;
925    
926 michael 7557 /* can_join() checks for +i, +l, key, bans, etc. */
927 michael 9250 int ret = can_join(client, channel, key);
928 michael 7557 if (ret)
929 michael 3912 {
930 michael 9250 sendto_one_numeric(client, &me, ret, channel->name);
931 michael 3912 continue;
932     }
933    
934     /*
935     * This should never be the case unless there is some sort of
936 michael 9250 * persistent channels.
937 michael 3912 */
938 michael 9081 if (dlink_list_length(&channel->members) == 0)
939 michael 3912 flags = CHFL_CHANOP;
940     else
941     flags = 0;
942     }
943     else
944     {
945     flags = CHFL_CHANOP;
946 michael 9081 channel = channel_make(name);
947 michael 3912 }
948    
949 michael 9250 if (!HasUMode(client, UMODE_OPER))
950     check_spambot_warning(client, channel->name);
951 michael 3912
952 michael 9250 add_user_to_channel(channel, client, flags, true);
953 michael 3912
954     /*
955 michael 5545 * Set timestamp if appropriate, and propagate
956 michael 3912 */
957     if (flags == CHFL_CHANOP)
958     {
959 michael 9081 channel->creation_time = event_base->time.sec_real;
960     AddCMode(channel, MODE_TOPICLIMIT);
961     AddCMode(channel, MODE_NOPRIVMSGS);
962 michael 3912
963 michael 8513 sendto_server(NULL, 0, 0, ":%s SJOIN %ju %s +nt :@%s",
964 michael 9081 me.id, channel->creation_time,
965 michael 9250 channel->name, client->id);
966 michael 3912
967     /*
968     * Notify all other users on the new channel
969     */
970 michael 9081 sendto_channel_local(NULL, channel, 0, CAP_EXTENDED_JOIN, 0, ":%s!%s@%s JOIN %s %s :%s",
971 michael 9250 client->name, client->username,
972     client->host, channel->name, client->account, client->info);
973 michael 9081 sendto_channel_local(NULL, channel, 0, 0, CAP_EXTENDED_JOIN, ":%s!%s@%s JOIN :%s",
974 michael 9250 client->name, client->username,
975     client->host, channel->name);
976 michael 9081 sendto_channel_local(NULL, channel, 0, 0, 0, ":%s MODE %s +nt",
977     me.name, channel->name);
978 michael 3912 }
979     else
980     {
981 michael 8513 sendto_server(NULL, 0, 0, ":%s JOIN %ju %s +",
982 michael 9250 client->id, channel->creation_time,
983 michael 9081 channel->name);
984 michael 3912
985 michael 9081 sendto_channel_local(NULL, channel, 0, CAP_EXTENDED_JOIN, 0, ":%s!%s@%s JOIN %s %s :%s",
986 michael 9250 client->name, client->username,
987     client->host, channel->name, client->account, client->info);
988 michael 9081 sendto_channel_local(NULL, channel, 0, 0, CAP_EXTENDED_JOIN, ":%s!%s@%s JOIN :%s",
989 michael 9250 client->name, client->username,
990     client->host, channel->name);
991 michael 3912 }
992    
993 michael 9250 if (client->away[0])
994     sendto_channel_local(client, channel, 0, CAP_AWAY_NOTIFY, 0,
995 michael 8542 ":%s!%s@%s AWAY :%s",
996 michael 9250 client->name, client->username,
997     client->host, client->away);
998 michael 8542
999 michael 9265 struct Invite *invite = invite_find(channel, client);
1000 michael 9200 if (invite)
1001 michael 9265 invite_del(invite);
1002 michael 3912
1003 michael 9081 if (channel->topic[0])
1004 michael 3912 {
1005 michael 9250 sendto_one_numeric(client, &me, RPL_TOPIC, channel->name, channel->topic);
1006     sendto_one_numeric(client, &me, RPL_TOPICWHOTIME, channel->name,
1007 michael 9081 channel->topic_info, channel->topic_time);
1008 michael 3912 }
1009    
1010 michael 9250 channel_member_names(client, channel, true);
1011 michael 3912
1012 michael 9250 client->connection->last_join_time = event_base->time.sec_monotonic;
1013 michael 3912 }
1014     }
1015    
1016     /*! \brief Removes a client from a specific channel
1017 michael 9250 * \param client Pointer to client to remove
1018     * \param name Name of channel to remove from
1019     * \param reason Part reason to show
1020 michael 3912 */
1021     static void
1022 michael 9250 channel_part_one_client(struct Client *client, const char *name, const char *reason)
1023 michael 3912 {
1024 michael 9365 struct Channel *channel = hash_find_channel(name);
1025     if (channel == NULL)
1026 michael 3912 {
1027 michael 9250 sendto_one_numeric(client, &me, ERR_NOSUCHCHANNEL, name);
1028 michael 3912 return;
1029     }
1030    
1031 michael 9365 struct ChannelMember *member = find_channel_link(client, channel);
1032     if (member == NULL)
1033 michael 3912 {
1034 michael 9250 sendto_one_numeric(client, &me, ERR_NOTONCHANNEL, channel->name);
1035 michael 3912 return;
1036     }
1037    
1038 michael 9250 if (MyConnect(client) && !HasUMode(client, UMODE_OPER))
1039     check_spambot_warning(client, NULL);
1040 michael 3912
1041     /*
1042 michael 9365 * Remove user from the old channel (if any). Only allow /part reasons in -m chans.
1043 michael 3912 */
1044 michael 9250 if (*reason && (!MyConnect(client) ||
1045     ((client->connection->created_monotonic +
1046 michael 8919 ConfigGeneral.anti_spam_exit_message_time) < event_base->time.sec_monotonic &&
1047 michael 9250 can_send(channel, client, member, reason, false) < 0)))
1048 michael 3912 {
1049 michael 9250 sendto_server(client, 0, 0, ":%s PART %s :%s",
1050     client->id, channel->name, reason);
1051 michael 9081 sendto_channel_local(NULL, channel, 0, 0, 0, ":%s!%s@%s PART %s :%s",
1052 michael 9250 client->name, client->username,
1053     client->host, channel->name, reason);
1054 michael 3912 }
1055     else
1056     {
1057 michael 9250 sendto_server(client, 0, 0, ":%s PART %s",
1058     client->id, channel->name);
1059 michael 9081 sendto_channel_local(NULL, channel, 0, 0, 0, ":%s!%s@%s PART %s",
1060 michael 9250 client->name, client->username,
1061     client->host, channel->name);
1062 michael 3912 }
1063    
1064 michael 4815 remove_user_from_channel(member);
1065 michael 3912 }
1066    
1067     void
1068 michael 9250 channel_do_part(struct Client *client, char *channel, const char *reason)
1069 michael 3912 {
1070 michael 7797 char *p = NULL;
1071 michael 4785 char buf[KICKLEN + 1] = "";
1072 michael 3912
1073 michael 9250 assert(IsClient(client));
1074 michael 5590
1075 michael 3937 if (!EmptyString(reason))
1076 michael 4785 strlcpy(buf, reason, sizeof(buf));
1077 michael 3912
1078 michael 7797 for (const char *name = strtok_r(channel, ",", &p); name;
1079     name = strtok_r(NULL, ",", &p))
1080 michael 9250 channel_part_one_client(client, name, buf);
1081 michael 3912 }

Properties

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