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 if(find_member_link(chptrb, sptr))
291 continue; //we have already joined this channel
292 //first of all check if we may even join this channel
294 if (chptrb->users == 0 && !chptrb->mode.apass[0] && !(chptrb->mode.mode & MODE_PERSIST)) {
295 /* Joining a zombie channel (zannel): give ops and increment TS. */
297 chptrb->creationtime++;
298 } else if (IsInvited(sptr, chptrb)) {
299 /* Invites and key=OVERRIDE bypass these other checks. */
300 } else if (chptrb->mode.mode & MODE_INVITEONLY)
301 err2 = ERR_INVITEONLYCHAN;
302 else if (chptrb->mode.limit && (chptrb->users >= chptrb->mode.limit))
303 err2 = ERR_CHANNELISFULL;
304 else if ((chptrb->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
305 err2 = ERR_NEEDREGGEDNICK;
306 else if (find_ban(sptr, chptrb->banlist))
307 err2 = ERR_BANNEDFROMCHAN;
308 else if (*chptrb->mode.key && (!key || strcmp(key, chptrb->mode.key)))
309 err2 = ERR_BADCHANNELKEY;
311 joinbuf_join(&join, chptrb, flags);
312 del_invite(sptr, chptrb);
313 if (chptrb->topic[0]) {
314 send_reply(sptr, RPL_TOPIC, chptrb->chname, chptrb->topic);
315 send_reply(sptr, RPL_TOPICWHOTIME, chptrb->chname, chptrb->topic_nick, chptrb->topic_time);
317 do_names(sptr, chptrb, NAMES_ALL|NAMES_EON|(((chptrb->mode.mode & MODE_AUDITORIUM) && !(flags & CHFL_CHANOP)) ? NAMES_OPS : 0)); /* send /names list */
323 const char *error = NULL;
324 if (err == ERR_CHANNELISFULL)
325 error = feature_str(FEAT_ERR_CHANNELISFULL);
326 else if (err == ERR_INVITEONLYCHAN)
327 error = feature_str(FEAT_ERR_INVITEONLYCHAN);
328 else if (err == ERR_BANNEDFROMCHAN)
329 error = feature_str(FEAT_ERR_BANNEDFROMCHAN);
330 else if (err == ERR_BADCHANNELKEY)
331 error = feature_str(FEAT_ERR_BADCHANNELKEY);
332 else if (err == ERR_NEEDREGGEDNICK)
333 error = feature_str(FEAT_ERR_NEEDREGGEDNICK);
334 else if (err == ERR_JOINACCESS)
335 error = feature_str(FEAT_ERR_JOINACCESS);
338 send_reply(sptr, err, chptr->chname, error);
340 send_reply(sptr, err, chptr->chname);
344 joinbuf_join(&join, chptr, flags);
345 if (flags & CHFL_CHANOP) {
347 /* Always let the server op him: this is needed on a net with older servers
348 because they 'destruct' channels immediately when they become empty without
349 sending out a DESTRUCT message. As a result, they would always bounce a mode
350 (as HACK(2)) when the user ops himself.
351 (There is also no particularly good reason to have the user op himself.)
353 modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
354 modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
355 chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
356 modebuf_flush(&mbuf);
360 del_invite(sptr, chptr);
362 if (chptr->topic[0]) {
363 send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
364 send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
368 do_names(sptr, chptr, NAMES_ALL|NAMES_EON|(((chptr->mode.mode & MODE_AUDITORIUM) && !(flags & CHFL_CHANOP)) ? NAMES_OPS : 0)); /* send /names list */
371 joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
372 joinbuf_flush(&create);
377 /** Handle a JOIN message from a server connection.
378 * See @ref m_functions for discussion of the arguments.
379 * @param[in] cptr Client that sent us the message.
380 * @param[in] sptr Original source of message.
381 * @param[in] parc Number of arguments.
382 * @param[in] parv Argument vector.
384 int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
386 struct Membership *member;
387 struct Channel *chptr;
390 unsigned int invisible;
398 return protocol_violation(cptr,
399 "%s tried to JOIN %s, duh!",
401 (parc < 2 || *parv[1] == '\0') ? "a channel" :
406 if (parc < 2 || *parv[1] == '\0')
407 return need_more_params(sptr, "JOIN");
409 if (parc > 2 && parv[2])
410 creation = atoi(parv[2]);
411 if (parc > 3 && parv[3])
412 invisible = atoi(parv[3]);
414 joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
416 chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
418 for (name = ircd_strtok(&p, chanlist, ","); name;
419 name = ircd_strtok(&p, 0, ",")) {
421 if (invisible == 1) {
422 flags = CHFL_DEOPPED | CHFL_INVISIBLE;
424 flags = CHFL_DEOPPED;
427 if (IsLocalChannel(name) || !IsChannelName(name))
429 protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
433 if (!(chptr = FindChannel(name)))
435 /* No channel exists, so create one */
436 if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
438 protocol_violation(sptr,"couldn't get channel %s for %s",
439 name,cli_name(sptr));
442 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
444 chptr->creationtime = creation;
445 const struct User* user = cli_user(sptr);
446 if (IsAccount(sptr)) {
447 //chptr->chanowner = user->account;
450 else { /* We have a valid channel? */
451 if ((member = find_member_link(chptr, sptr)))
453 /* It is impossible to get here --Run */
454 if (!IsZombie(member)) /* already on channel */
456 if (invisible == 1) {
457 flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK | CHFL_INVISIBLE);
459 flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
461 remove_user_from_channel(sptr, chptr);
462 chptr = FindChannel(name);
465 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
467 /* Always copy the timestamp when it is older, that is the only way to
468 ensure network-wide synchronization of creation times.
469 We now also copy a creation time that only 1 second younger...
470 this is needed because the timestamp must be incremented
471 by one when someone joins an existing, but empty, channel.
472 However, this is only necessary when the channel is still
473 empty (also here) and when this channel doesn't have +A set.
475 To prevent this from allowing net-rides on the channel, we
476 clear all modes from the channel.
478 (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
479 user in the channel; c1 parts and rejoins, gaining ops.
480 Before s2 sees c1's part, c2 joins the channel and parts
481 immediately. s1 sees c1 part, c1 create, c2 join, c2 part;
482 c2's join resets the timestamp. s2 sees c2 join, c2 part, c1
483 part, c1 create; but since s2 sees the channel as a zannel or
484 non-existent, it does not bounce the create with the newer
487 if (creation && (creation < chptr->creationtime ||
488 (!chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST) && chptr->users == 0))) {
489 struct Membership *member;
492 chptr->creationtime = creation;
493 /* Wipe out the current modes on the channel. */
494 modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3);
496 modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
497 chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
499 if (chptr->mode.limit) {
500 modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
501 chptr->mode.limit = 0;
504 if (chptr->mode.key[0]) {
505 modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
506 chptr->mode.key[0] = '\0';
509 if (chptr->mode.upass[0]) {
510 modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
511 chptr->mode.upass[0] = '\0';
514 if (chptr->mode.apass[0]) {
515 modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
516 chptr->mode.apass[0] = '\0';
519 for (member = chptr->members; member; member = member->next_member)
521 if (IsChanOp(member)) {
522 modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
523 member->status &= ~CHFL_CHANOP;
525 if (HasVoice(member)) {
526 modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member));
527 member->status &= ~CHFL_VOICE;
530 modebuf_flush(&mbuf);
534 joinbuf_join(&join, chptr, flags);
537 joinbuf_flush(&join); /* flush joins... */