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 joinbuf_join(&join, chptrb, flags);
289 del_invite(sptr, chptrb);
290 if (chptrb->topic[0]) {
291 send_reply(sptr, RPL_TOPIC, chptrb->chname, chptrb->topic);
292 send_reply(sptr, RPL_TOPICWHOTIME, chptrb->chname, chptrb->topic_nick, chptrb->topic_time);
294 do_names(sptr, chptrb, NAMES_ALL|NAMES_EON); /* send /names list */
300 case ERR_NEEDREGGEDNICK:
304 feature_str(FEAT_URLREG));
307 send_reply(sptr, err, chptr->chname);
313 joinbuf_join(&join, chptr, flags);
314 if (flags & CHFL_CHANOP) {
316 /* Always let the server op him: this is needed on a net with older servers
317 because they 'destruct' channels immediately when they become empty without
318 sending out a DESTRUCT message. As a result, they would always bounce a mode
319 (as HACK(2)) when the user ops himself.
320 (There is also no particularly good reason to have the user op himself.)
322 modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
323 modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
324 chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
325 modebuf_flush(&mbuf);
329 del_invite(sptr, chptr);
331 if (chptr->topic[0]) {
332 send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
333 send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
337 do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */
340 joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
341 joinbuf_flush(&create);
346 /** Handle a JOIN message from a server connection.
347 * See @ref m_functions for discussion of the arguments.
348 * @param[in] cptr Client that sent us the message.
349 * @param[in] sptr Original source of message.
350 * @param[in] parc Number of arguments.
351 * @param[in] parv Argument vector.
353 int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
355 struct Membership *member;
356 struct Channel *chptr;
359 unsigned int invisible;
367 return protocol_violation(cptr,
368 "%s tried to JOIN %s, duh!",
370 (parc < 2 || *parv[1] == '\0') ? "a channel" :
375 if (parc < 2 || *parv[1] == '\0')
376 return need_more_params(sptr, "JOIN");
378 if (parc > 2 && parv[2])
379 creation = atoi(parv[2]);
380 if (parc > 3 && parv[3])
381 invisible = atoi(parv[3]);
383 joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
385 chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
387 for (name = ircd_strtok(&p, chanlist, ","); name;
388 name = ircd_strtok(&p, 0, ",")) {
390 if (invisible == 1) {
391 flags = CHFL_DEOPPED | CHFL_INVISIBLE;
393 flags = CHFL_DEOPPED;
396 if (IsLocalChannel(name) || !IsChannelName(name))
398 protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
402 if (!(chptr = FindChannel(name)))
404 /* No channel exists, so create one */
405 if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
407 protocol_violation(sptr,"couldn't get channel %s for %s",
408 name,cli_name(sptr));
411 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
413 chptr->creationtime = creation;
414 const struct User* user = cli_user(sptr);
415 if (IsAccount(sptr)) {
416 //chptr->chanowner = user->account;
419 else { /* We have a valid channel? */
420 if ((member = find_member_link(chptr, sptr)))
422 /* It is impossible to get here --Run */
423 if (!IsZombie(member)) /* already on channel */
425 if (invisible == 1) {
426 flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK | CHFL_INVISIBLE);
428 flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
430 remove_user_from_channel(sptr, chptr);
431 chptr = FindChannel(name);
434 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
436 /* Always copy the timestamp when it is older, that is the only way to
437 ensure network-wide synchronization of creation times.
438 We now also copy a creation time that only 1 second younger...
439 this is needed because the timestamp must be incremented
440 by one when someone joins an existing, but empty, channel.
441 However, this is only necessary when the channel is still
442 empty (also here) and when this channel doesn't have +A set.
444 To prevent this from allowing net-rides on the channel, we
445 clear all modes from the channel.
447 (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
448 user in the channel; c1 parts and rejoins, gaining ops.
449 Before s2 sees c1's part, c2 joins the channel and parts
450 immediately. s1 sees c1 part, c1 create, c2 join, c2 part;
451 c2's join resets the timestamp. s2 sees c2 join, c2 part, c1
452 part, c1 create; but since s2 sees the channel as a zannel or
453 non-existent, it does not bounce the create with the newer
456 if (creation && (creation < chptr->creationtime ||
457 (!chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST) && chptr->users == 0))) {
458 struct Membership *member;
461 chptr->creationtime = creation;
462 /* Wipe out the current modes on the channel. */
463 modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3);
465 modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
466 chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
468 if (chptr->mode.limit) {
469 modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
470 chptr->mode.limit = 0;
473 if (chptr->mode.key[0]) {
474 modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
475 chptr->mode.key[0] = '\0';
478 if (chptr->mode.upass[0]) {
479 modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
480 chptr->mode.upass[0] = '\0';
483 if (chptr->mode.apass[0]) {
484 modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
485 chptr->mode.apass[0] = '\0';
488 for (member = chptr->members; member; member = member->next_member)
490 if (IsChanOp(member)) {
491 modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
492 member->status &= ~CHFL_CHANOP;
494 if (HasVoice(member)) {
495 modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member));
496 member->status &= ~CHFL_VOICE;
499 modebuf_flush(&mbuf);
503 joinbuf_join(&join, chptr, flags);
506 joinbuf_flush(&join); /* flush joins... */