2 * IRC - Internet Relay Chat, ircd/m_join.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
6 * See file AUTHORS in IRC package for additional names of
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 1, or (at your option)
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * $Id: m_join.c 1906 2009-02-09 03:39:42Z entrope $
34 #include "ircd_chattr.h"
35 #include "ircd_features.h"
37 #include "ircd_reply.h"
38 #include "ircd_string.h"
49 /* #include <assert.h> -- Now using assert in ircd_log.h */
53 /** Searches for and handles a 0 in a join list.
54 * @param[in] cptr Client that sent us the message.
55 * @param[in] sptr Original source of message.
56 * @param[in] chanlist List of channels to join.
57 * @return First token in \a chanlist after the final 0 entry, which
58 * may be its nul terminator (if the final entry is a 0 entry).
61 last0(struct Client *cptr, struct Client *sptr, char *chanlist)
66 for (p = chanlist; p[0]; p++) /* find last "JOIN 0" */
67 if (p[0] == '0' && (p[1] == ',' || p[1] == '\0')) {
73 while (p[0] != ',' && p[0] != '\0') /* skip past channel name */
76 if (!p[0]) /* hit the end */
82 struct Membership *member;
84 joinbuf_init(&part, sptr, cptr, JOINBUF_TYPE_PARTALL,
85 "Left all channels", 0);
87 joinbuf_join(&part, 0, 0);
89 while ((member = cli_user(sptr)->channel))
90 joinbuf_join(&part, member->channel,
91 IsZombie(member) ? CHFL_ZOMBIE :
92 IsDelayedJoin(member) ? CHFL_DELAYED :
101 /** Handle a JOIN message from a client connection.
102 * See @ref m_functions for discussion of the arguments.
103 * @param[in] cptr Client that sent us the message.
104 * @param[in] sptr Original source of message.
105 * @param[in] parc Number of arguments.
106 * @param[in] parv Argument vector.
108 int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
110 struct Channel *chptr,*chptrb;
112 struct JoinBuf create;
114 struct Membership *member;
119 unsigned int maxchans;
120 const struct User* user = cli_user(sptr);
122 if (parc < 2 || *parv[1] == '\0')
123 return need_more_params(sptr, "JOIN");
125 joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
126 joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime());
128 chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
130 keys = parv[2]; /* remember where keys are */
132 for (name = ircd_strtok(&p, chanlist, ","); name;
133 name = ircd_strtok(&p, 0, ",")) {
136 /* If we have any more keys, take the first for this channel. */
138 && (keys = strchr(key = keys, ',')))
141 /* Empty keys are the same as no keys. */
145 if (!IsChannelName(name) || !strIsIrcCh(name))
147 /* bad channel name */
148 send_reply(sptr, ERR_NOSUCHCHANNEL, name);
152 maxchans = cli_confs(sptr)->value.aconf ? ConfMaxChannels(cli_confs(sptr)->value.aconf) : feature_int(FEAT_MAXCHANNELSPERUSER);
153 if(sptr->maxchans > 0)
154 maxchans = sptr->maxchans;
155 if (cli_user(sptr)->joined >= maxchans
156 && !HasPriv(sptr, PRIV_CHAN_LIMIT)) {
157 send_reply(sptr, ERR_TOOMANYCHANNELS, name);
158 break; /* no point processing the other channels */
161 /* BADCHANed channel */
162 if ((gline = gline_find(name, GLINE_BADCHAN)) &&
163 GlineIsActive(gline) && !IsAnOper(sptr)) {
164 send_reply(sptr, ERR_BADCHANNAME, name, GlineReason(gline));
168 if (!(chptr = FindChannel(name))) {
169 if (((name[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS))
170 || strlen(name) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
171 send_reply(sptr, ERR_NOSUCHCHANNEL, name);
175 if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
178 /* Try to add the new channel as a recent target for the user. */
179 if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
181 destruct_channel(chptr);
185 joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
186 } else if (member = find_member_link(chptr, sptr)) {
187 if(IsDelayedJoin(member) && IsInvisibleJoin(member)) {
188 ClearInvisibleJoin(member);
189 RevealDelayedJoinIfNeeded(sptr, chptr);
192 } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
195 int flags = CHFL_DEOPPED;
199 /* Check Apass/Upass -- since we only ever look at a single
200 * "key" per channel now, this hampers brute force attacks. */
201 if (key && !strcmp(key, chptr->mode.apass))
202 flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER;
203 else if (key && !strcmp(key, chptr->mode.upass))
205 else if (chptr->users == 0 && !chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST)) {
206 /* Joining a zombie channel (zannel): give ops and increment TS. */
208 chptr->creationtime++;
209 } else if (IsInvited(sptr, chptr) || (IsXtraOp(sptr) && key && strcmp(key, "OVERRIDE") == 0)) {
210 /* Invites and key=OVERRIDE bypass these other checks. */
211 } else if (chptr->mode.mode & MODE_INVITEONLY)
212 err = ERR_INVITEONLYCHAN;
213 else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit))
214 err = ERR_CHANNELISFULL;
215 else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
216 err = ERR_NEEDREGGEDNICK;
217 else if (find_ban(sptr, chptr->banlist))
218 err = ERR_BANNEDFROMCHAN;
219 else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)))
220 err = ERR_BADCHANNELKEY;
224 /* An oper with WALK_LCHAN privilege can join a local channel
225 * he otherwise could not join by using "OVERRIDE" as the key.
226 * This will generate a HACK(4) notice, but fails if the oper
227 * could normally join the channel. */
228 if (HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV) && key && !strcmp(key, "INVISIBLE")) {
229 sendto_opmask_butone(0, SNO_HACK4, "INVISIBLE JOIN: %C JOIN %H", sptr, chptr);
230 flags = CHFL_INVISIBLE;
235 if ((HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV))
236 && !(flags & CHFL_CHANOP)
237 && key && !strcmp(key, "OVERRIDE"))
241 if (strcmp(chptr->mode.key, "OVERRIDE")
242 && strcmp(chptr->mode.apass, "OVERRIDE")
243 && strcmp(chptr->mode.upass, "OVERRIDE")) {
244 send_reply(sptr, ERR_DONTCHEAT, chptr->chname);
248 case ERR_INVITEONLYCHAN: err = 'i'; break;
249 case ERR_CHANNELISFULL: err = 'l'; break;
250 case ERR_BANNEDFROMCHAN: err = 'b'; break;
251 case ERR_BADCHANNELKEY: err = 'k'; break;
252 case ERR_NEEDREGGEDNICK: err = 'r'; break;
253 default: err = '?'; break;
255 /* send accountability notice */
257 sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H "
258 "(overriding +%c)", sptr, chptr, err);
263 if(!err && !override && !IsInvited(sptr, chptr) && chptr->mode.access && chptr->mode.access > 0 && chptr->mode.access < 500 && feature_bool(FEAT_CHMODE_A_ENABLE)) {
264 //We have to check the users channel access...
265 struct Client *acptr;
266 if(feature_str(FEAT_CHMODE_A_TARGET) && (acptr = FindUser(feature_str(FEAT_CHMODE_A_TARGET))) && IsNetServ(acptr) && IsService(cli_user(acptr)->server)) {
267 sendcmdto_one(&me, CMD_RELAY, acptr, "%C JA %C %s %i %i", acptr, sptr, chptr->chname, chptr->mode.access, flags);
268 continue; // We can't do anything more here... We have to wait for the response...
270 if(feature_str(FEAT_CHMODE_A_TARGET))
271 send_reply(sptr, ERR_SERVICESDOWN, feature_str(FEAT_CHMODE_A_TARGET));
272 err = ERR_JOINACCESS;
276 /* Is there some reason the user may not join? */
277 if(err && chptr->mode.altchan && IsChannelName(chptr->mode.altchan) && strIsIrcCh(chptr->mode.altchan)) {
278 char *altchan = chptr->mode.altchan;
280 if (!(chptrb = FindChannel(altchan))) {
281 if (((altchan[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(altchan) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
282 //we don't send an error message here - that would be very strange for the user, because they normaly don't know that mode +F is set
283 } else if ((chptrb = get_channel(sptr, altchan, CGT_CREATE))) {
284 joinbuf_join(&create, chptrb, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
285 do_names(sptr, chptrb, NAMES_ALL|NAMES_EON);
288 //first of all check if we may even join this channel
290 if (chptrb->users == 0 && !chptrb->mode.apass[0] && !(chptrb->mode.mode & MODE_PERSIST)) {
291 /* Joining a zombie channel (zannel): give ops and increment TS. */
293 chptrb->creationtime++;
294 } else if (IsInvited(sptr, chptrb)) {
295 /* Invites and key=OVERRIDE bypass these other checks. */
296 } else if (chptrb->mode.mode & MODE_INVITEONLY)
297 err2 = ERR_INVITEONLYCHAN;
298 else if (chptrb->mode.limit && (chptrb->users >= chptrb->mode.limit))
299 err2 = ERR_CHANNELISFULL;
300 else if ((chptrb->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
301 err2 = ERR_NEEDREGGEDNICK;
302 else if (find_ban(sptr, chptrb->banlist))
303 err2 = ERR_BANNEDFROMCHAN;
304 else if (*chptrb->mode.key && (!key || strcmp(key, chptrb->mode.key)))
305 err2 = ERR_BADCHANNELKEY;
307 joinbuf_join(&join, chptrb, flags);
308 del_invite(sptr, chptrb);
309 if (chptrb->topic[0]) {
310 send_reply(sptr, RPL_TOPIC, chptrb->chname, chptrb->topic);
311 send_reply(sptr, RPL_TOPICWHOTIME, chptrb->chname, chptrb->topic_nick, chptrb->topic_time);
313 do_names(sptr, chptrb, NAMES_ALL|NAMES_EON); /* send /names list */
320 case ERR_NEEDREGGEDNICK:
324 feature_str(FEAT_URLREG));
327 send_reply(sptr, err, chptr->chname);
333 joinbuf_join(&join, chptr, flags);
334 if (flags & CHFL_CHANOP) {
336 /* Always let the server op him: this is needed on a net with older servers
337 because they 'destruct' channels immediately when they become empty without
338 sending out a DESTRUCT message. As a result, they would always bounce a mode
339 (as HACK(2)) when the user ops himself.
340 (There is also no particularly good reason to have the user op himself.)
342 modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
343 modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
344 chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
345 modebuf_flush(&mbuf);
349 del_invite(sptr, chptr);
351 if (chptr->topic[0]) {
352 send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
353 send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
357 do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */
360 joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
361 joinbuf_flush(&create);
366 /** Handle a JOIN message from a server connection.
367 * See @ref m_functions for discussion of the arguments.
368 * @param[in] cptr Client that sent us the message.
369 * @param[in] sptr Original source of message.
370 * @param[in] parc Number of arguments.
371 * @param[in] parv Argument vector.
373 int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
375 struct Membership *member;
376 struct Channel *chptr;
379 unsigned int invisible;
387 return protocol_violation(cptr,
388 "%s tried to JOIN %s, duh!",
390 (parc < 2 || *parv[1] == '\0') ? "a channel" :
395 if (parc < 2 || *parv[1] == '\0')
396 return need_more_params(sptr, "JOIN");
398 if (parc > 2 && parv[2])
399 creation = atoi(parv[2]);
400 if (parc > 3 && parv[3])
401 invisible = atoi(parv[3]);
403 joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
405 chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
407 for (name = ircd_strtok(&p, chanlist, ","); name;
408 name = ircd_strtok(&p, 0, ",")) {
410 if (invisible == 1) {
411 flags = CHFL_DEOPPED | CHFL_INVISIBLE;
413 flags = CHFL_DEOPPED;
416 if (IsLocalChannel(name) || !IsChannelName(name))
418 protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
422 if (!(chptr = FindChannel(name)))
424 /* No channel exists, so create one */
425 if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
427 protocol_violation(sptr,"couldn't get channel %s for %s",
428 name,cli_name(sptr));
431 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
433 chptr->creationtime = creation;
434 const struct User* user = cli_user(sptr);
435 if (IsAccount(sptr)) {
436 //chptr->chanowner = user->account;
439 else { /* We have a valid channel? */
440 if ((member = find_member_link(chptr, sptr)))
442 /* It is impossible to get here --Run */
443 if (!IsZombie(member)) /* already on channel */
445 if (invisible == 1) {
446 flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK | CHFL_INVISIBLE);
448 flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
450 remove_user_from_channel(sptr, chptr);
451 chptr = FindChannel(name);
454 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
456 /* Always copy the timestamp when it is older, that is the only way to
457 ensure network-wide synchronization of creation times.
458 We now also copy a creation time that only 1 second younger...
459 this is needed because the timestamp must be incremented
460 by one when someone joins an existing, but empty, channel.
461 However, this is only necessary when the channel is still
462 empty (also here) and when this channel doesn't have +A set.
464 To prevent this from allowing net-rides on the channel, we
465 clear all modes from the channel.
467 (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
468 user in the channel; c1 parts and rejoins, gaining ops.
469 Before s2 sees c1's part, c2 joins the channel and parts
470 immediately. s1 sees c1 part, c1 create, c2 join, c2 part;
471 c2's join resets the timestamp. s2 sees c2 join, c2 part, c1
472 part, c1 create; but since s2 sees the channel as a zannel or
473 non-existent, it does not bounce the create with the newer
476 if (creation && (creation < chptr->creationtime ||
477 (!chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST) && chptr->users == 0))) {
478 struct Membership *member;
481 chptr->creationtime = creation;
482 /* Wipe out the current modes on the channel. */
483 modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3);
485 modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
486 chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
488 if (chptr->mode.limit) {
489 modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
490 chptr->mode.limit = 0;
493 if (chptr->mode.key[0]) {
494 modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
495 chptr->mode.key[0] = '\0';
498 if (chptr->mode.upass[0]) {
499 modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
500 chptr->mode.upass[0] = '\0';
503 if (chptr->mode.apass[0]) {
504 modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
505 chptr->mode.apass[0] = '\0';
508 for (member = chptr->members; member; member = member->next_member)
510 if (IsChanOp(member)) {
511 modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
512 member->status &= ~CHFL_CHANOP;
514 if (HasVoice(member)) {
515 modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member));
516 member->status &= ~CHFL_VOICE;
519 modebuf_flush(&mbuf);
523 joinbuf_join(&join, chptr, flags);
526 joinbuf_flush(&join); /* flush joins... */