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 */
163 /* BADCHANed channel */
164 if ((gline = gline_find(name, GLINE_BADCHAN)) &&
165 GlineIsActive(gline) && !IsAnOper(sptr)) {
166 send_reply(sptr, ERR_BADCHANNAME, name, GlineReason(gline));
170 if (!(chptr = FindChannel(name))) {
171 if (((name[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS))
172 || strlen(name) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
173 send_reply(sptr, ERR_NOSUCHCHANNEL, name);
177 if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
180 /* Try to add the new channel as a recent target for the user. */
181 if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
183 destruct_channel(chptr);
187 joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
188 } else if (member = find_member_link(chptr, sptr)) {
189 if(IsDelayedJoin(member) && IsInvisibleJoin(member)) {
190 ClearInvisibleJoin(member);
191 RevealDelayedJoinIfNeeded(sptr, chptr);
194 } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
197 flags = CHFL_DEOPPED;
201 /* Check Apass/Upass -- since we only ever look at a single
202 * "key" per channel now, this hampers brute force attacks. */
203 if (key && !strcmp(key, chptr->mode.apass))
204 flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER;
205 else if (key && !strcmp(key, chptr->mode.upass))
207 else if (chptr->users == 0 && !chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST)) {
208 /* Joining a zombie channel (zannel): give ops and increment TS. */
210 chptr->creationtime++;
211 } else if (IsInvited(sptr, chptr) || (IsXtraOp(sptr) && key && strcmp(key, "OVERRIDE") == 0)) {
212 /* Invites and key=OVERRIDE bypass these other checks. */
213 } else if (chptr->mode.mode & MODE_INVITEONLY)
214 err = ERR_INVITEONLYCHAN;
215 else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit))
216 err = ERR_CHANNELISFULL;
217 else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
218 err = ERR_NEEDREGGEDNICK;
219 else if (find_ban(sptr, chptr->banlist))
220 err = ERR_BANNEDFROMCHAN;
221 else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)))
222 err = ERR_BADCHANNELKEY;
226 /* An oper with WALK_LCHAN privilege can join a local channel
227 * he otherwise could not join by using "OVERRIDE" as the key.
228 * This will generate a HACK(4) notice, but fails if the oper
229 * could normally join the channel. */
230 if (HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV) && key && !strcmp(key, "INVISIBLE")) {
231 sendto_opmask_butone(0, SNO_HACK4, "INVISIBLE JOIN: %C JOIN %H", sptr, chptr);
232 flags = CHFL_INVISIBLE;
237 if ((HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV))
238 && !(flags & CHFL_CHANOP)
239 && key && !strcmp(key, "OVERRIDE"))
243 if (strcmp(chptr->mode.key, "OVERRIDE")
244 && strcmp(chptr->mode.apass, "OVERRIDE")
245 && strcmp(chptr->mode.upass, "OVERRIDE")) {
246 send_reply(sptr, ERR_DONTCHEAT, chptr->chname);
250 case ERR_INVITEONLYCHAN: err = 'i'; break;
251 case ERR_CHANNELISFULL: err = 'l'; break;
252 case ERR_BANNEDFROMCHAN: err = 'b'; break;
253 case ERR_BADCHANNELKEY: err = 'k'; break;
254 case ERR_NEEDREGGEDNICK: err = 'r'; break;
255 default: err = '?'; break;
257 /* send accountability notice */
259 sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H "
260 "(overriding +%c)", sptr, chptr, err);
265 if(!err && !override && !IsInvited(sptr, chptr) && chptr->mode.access && chptr->mode.access > 0 && chptr->mode.access < 500 && feature_bool(FEAT_CHMODE_A_ENABLE)) {
266 //We have to check the users channel access...
267 struct Client *acptr;
268 if(feature_str(FEAT_CHMODE_A_TARGET) && (acptr = FindUser(feature_str(FEAT_CHMODE_A_TARGET))) && IsNetServ(acptr) && IsService(cli_user(acptr)->server)) {
269 sendcmdto_one(&me, CMD_RELAY, acptr, "%C JA %C %s %i %i", acptr, sptr, chptr->chname, chptr->mode.access, flags);
270 continue; // We can't do anything more here... We have to wait for the response...
272 if(feature_str(FEAT_CHMODE_A_TARGET))
273 send_reply(sptr, ERR_SERVICESDOWN, feature_str(FEAT_CHMODE_A_TARGET));
274 err = ERR_JOINACCESS;
278 /* Is there some reason the user may not join? */
279 if(err && chptr->mode.altchan && IsChannelName(chptr->mode.altchan) && strIsIrcCh(chptr->mode.altchan)) {
280 char *altchan = chptr->mode.altchan;
282 if (!(chptrb = FindChannel(altchan))) {
283 if (((altchan[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(altchan) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
284 //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
285 } else if ((chptrb = get_channel(sptr, altchan, CGT_CREATE))) {
286 joinbuf_join(&create, chptrb, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
287 do_names(sptr, chptrb, NAMES_ALL|NAMES_EON);
290 //first of all check if we may even join this channel
292 if (chptrb->users == 0 && !chptrb->mode.apass[0] && !(chptrb->mode.mode & MODE_PERSIST)) {
293 /* Joining a zombie channel (zannel): give ops and increment TS. */
295 chptrb->creationtime++;
296 } else if (IsInvited(sptr, chptrb)) {
297 /* Invites and key=OVERRIDE bypass these other checks. */
298 } else if (chptrb->mode.mode & MODE_INVITEONLY)
299 err2 = ERR_INVITEONLYCHAN;
300 else if (chptrb->mode.limit && (chptrb->users >= chptrb->mode.limit))
301 err2 = ERR_CHANNELISFULL;
302 else if ((chptrb->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
303 err2 = ERR_NEEDREGGEDNICK;
304 else if (find_ban(sptr, chptrb->banlist))
305 err2 = ERR_BANNEDFROMCHAN;
306 else if (*chptrb->mode.key && (!key || strcmp(key, chptrb->mode.key)))
307 err2 = ERR_BADCHANNELKEY;
309 joinbuf_join(&join, chptrb, flags);
310 del_invite(sptr, chptrb);
311 if (chptrb->topic[0]) {
312 send_reply(sptr, RPL_TOPIC, chptrb->chname, chptrb->topic);
313 send_reply(sptr, RPL_TOPICWHOTIME, chptrb->chname, chptrb->topic_nick, chptrb->topic_time);
315 do_names(sptr, chptrb, NAMES_ALL|NAMES_EON|(((chptrb->mode.mode & MODE_AUDITORIUM) && !(flags & CHFL_CHANOP)) ? NAMES_OPS : 0)); /* send /names list */
322 case ERR_NEEDREGGEDNICK:
326 feature_str(FEAT_URLREG));
329 send_reply(sptr, err, chptr->chname);
335 joinbuf_join(&join, chptr, flags);
336 if (flags & CHFL_CHANOP) {
338 /* Always let the server op him: this is needed on a net with older servers
339 because they 'destruct' channels immediately when they become empty without
340 sending out a DESTRUCT message. As a result, they would always bounce a mode
341 (as HACK(2)) when the user ops himself.
342 (There is also no particularly good reason to have the user op himself.)
344 modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
345 modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
346 chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
347 modebuf_flush(&mbuf);
351 del_invite(sptr, chptr);
353 if (chptr->topic[0]) {
354 send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
355 send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
359 do_names(sptr, chptr, NAMES_ALL|NAMES_EON|(((chptr->mode.mode & MODE_AUDITORIUM) && !(flags & CHFL_CHANOP)) ? NAMES_OPS : 0)); /* send /names list */
362 joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
363 joinbuf_flush(&create);
368 /** Handle a JOIN message from a server connection.
369 * See @ref m_functions for discussion of the arguments.
370 * @param[in] cptr Client that sent us the message.
371 * @param[in] sptr Original source of message.
372 * @param[in] parc Number of arguments.
373 * @param[in] parv Argument vector.
375 int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
377 struct Membership *member;
378 struct Channel *chptr;
381 unsigned int invisible;
389 return protocol_violation(cptr,
390 "%s tried to JOIN %s, duh!",
392 (parc < 2 || *parv[1] == '\0') ? "a channel" :
397 if (parc < 2 || *parv[1] == '\0')
398 return need_more_params(sptr, "JOIN");
400 if (parc > 2 && parv[2])
401 creation = atoi(parv[2]);
402 if (parc > 3 && parv[3])
403 invisible = atoi(parv[3]);
405 joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
407 chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
409 for (name = ircd_strtok(&p, chanlist, ","); name;
410 name = ircd_strtok(&p, 0, ",")) {
412 if (invisible == 1) {
413 flags = CHFL_DEOPPED | CHFL_INVISIBLE;
415 flags = CHFL_DEOPPED;
418 if (IsLocalChannel(name) || !IsChannelName(name))
420 protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
424 if (!(chptr = FindChannel(name)))
426 /* No channel exists, so create one */
427 if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
429 protocol_violation(sptr,"couldn't get channel %s for %s",
430 name,cli_name(sptr));
433 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
435 chptr->creationtime = creation;
436 const struct User* user = cli_user(sptr);
437 if (IsAccount(sptr)) {
438 //chptr->chanowner = user->account;
441 else { /* We have a valid channel? */
442 if ((member = find_member_link(chptr, sptr)))
444 /* It is impossible to get here --Run */
445 if (!IsZombie(member)) /* already on channel */
447 if (invisible == 1) {
448 flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK | CHFL_INVISIBLE);
450 flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
452 remove_user_from_channel(sptr, chptr);
453 chptr = FindChannel(name);
456 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
458 /* Always copy the timestamp when it is older, that is the only way to
459 ensure network-wide synchronization of creation times.
460 We now also copy a creation time that only 1 second younger...
461 this is needed because the timestamp must be incremented
462 by one when someone joins an existing, but empty, channel.
463 However, this is only necessary when the channel is still
464 empty (also here) and when this channel doesn't have +A set.
466 To prevent this from allowing net-rides on the channel, we
467 clear all modes from the channel.
469 (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
470 user in the channel; c1 parts and rejoins, gaining ops.
471 Before s2 sees c1's part, c2 joins the channel and parts
472 immediately. s1 sees c1 part, c1 create, c2 join, c2 part;
473 c2's join resets the timestamp. s2 sees c2 join, c2 part, c1
474 part, c1 create; but since s2 sees the channel as a zannel or
475 non-existent, it does not bounce the create with the newer
478 if (creation && (creation < chptr->creationtime ||
479 (!chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST) && chptr->users == 0))) {
480 struct Membership *member;
483 chptr->creationtime = creation;
484 /* Wipe out the current modes on the channel. */
485 modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3);
487 modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
488 chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
490 if (chptr->mode.limit) {
491 modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
492 chptr->mode.limit = 0;
495 if (chptr->mode.key[0]) {
496 modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
497 chptr->mode.key[0] = '\0';
500 if (chptr->mode.upass[0]) {
501 modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
502 chptr->mode.upass[0] = '\0';
505 if (chptr->mode.apass[0]) {
506 modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
507 chptr->mode.apass[0] = '\0';
510 for (member = chptr->members; member; member = member->next_member)
512 if (IsChanOp(member)) {
513 modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
514 member->status &= ~CHFL_CHANOP;
516 if (HasVoice(member)) {
517 modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member));
518 member->status &= ~CHFL_VOICE;
521 modebuf_flush(&mbuf);
525 joinbuf_join(&join, chptr, flags);
528 joinbuf_flush(&join); /* flush joins... */