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 ((chptr->mode.mode & MODE_SSLCHAN) && !IsSSL(sptr))
220 err = ERR_SSLCHANNEL;
221 else if (find_ban(sptr, chptr->banlist))
222 err = ERR_BANNEDFROMCHAN;
223 else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)))
224 err = ERR_BADCHANNELKEY;
228 /* An oper with WALK_LCHAN privilege can join a local channel
229 * he otherwise could not join by using "OVERRIDE" as the key.
230 * This will generate a HACK(4) notice, but fails if the oper
231 * could normally join the channel. */
232 if (HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV) && key && !strcmp(key, "INVISIBLE")) {
233 sendto_opmask_butone(0, SNO_HACK4, "INVISIBLE JOIN: %C JOIN %H", sptr, chptr);
234 flags = CHFL_INVISIBLE;
239 if ((HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV))
240 && !(flags & CHFL_CHANOP)
241 && key && !strcmp(key, "OVERRIDE"))
245 if (strcmp(chptr->mode.key, "OVERRIDE")
246 && strcmp(chptr->mode.apass, "OVERRIDE")
247 && strcmp(chptr->mode.upass, "OVERRIDE")) {
248 send_reply(sptr, ERR_DONTCHEAT, chptr->chname);
252 case ERR_INVITEONLYCHAN: err = 'i'; break;
253 case ERR_CHANNELISFULL: err = 'l'; break;
254 case ERR_BANNEDFROMCHAN: err = 'b'; break;
255 case ERR_BADCHANNELKEY: err = 'k'; break;
256 case ERR_NEEDREGGEDNICK: err = 'r'; break;
257 case ERR_SSLCHANNEL: err = 'S'; break;
258 default: err = '?'; break;
260 /* send accountability notice */
262 sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H "
263 "(overriding +%c)", sptr, chptr, err);
268 if(!err && !override && !IsInvited(sptr, chptr) && chptr->mode.access && chptr->mode.access > 0 && chptr->mode.access <= 500 && feature_bool(FEAT_CHMODE_A_ENABLE)) {
269 //We have to check the users channel access...
270 struct Client *acptr;
271 if(feature_str(FEAT_CHMODE_A_TARGET) && (acptr = FindUser(feature_str(FEAT_CHMODE_A_TARGET))) && IsNetServ(acptr) && IsService(cli_user(acptr)->server)) {
272 sendcmdto_one(&me, CMD_RELAY, acptr, "%C JA %C %s %i %i", acptr, sptr, chptr->chname, chptr->mode.access, flags);
273 continue; // We can't do anything more here... We have to wait for the response...
275 if(feature_str(FEAT_CHMODE_A_TARGET))
276 send_reply(sptr, ERR_SERVICESDOWN, feature_str(FEAT_CHMODE_A_TARGET));
277 err = ERR_JOINACCESS;
281 /* Is there some reason the user may not join? */
282 if(err && chptr->mode.altchan && IsChannelName(chptr->mode.altchan) && strIsIrcCh(chptr->mode.altchan)) {
283 char *altchan = chptr->mode.altchan;
285 if (!(chptrb = FindChannel(altchan))) {
286 if (((altchan[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(altchan) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
287 //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
288 } else if ((chptrb = get_channel(sptr, altchan, CGT_CREATE))) {
289 joinbuf_join(&create, chptrb, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
290 do_names(sptr, chptrb, NAMES_ALL|NAMES_EON);
293 if(find_member_link(chptrb, sptr))
294 continue; //we have already joined this channel
295 //first of all check if we may even join this channel
297 if (chptrb->users == 0 && !chptrb->mode.apass[0] && !(chptrb->mode.mode & MODE_PERSIST)) {
298 /* Joining a zombie channel (zannel): give ops and increment TS. */
300 chptrb->creationtime++;
301 } else if (IsInvited(sptr, chptrb)) {
302 /* Invites and key=OVERRIDE bypass these other checks. */
303 } else if (chptrb->mode.mode & MODE_INVITEONLY)
304 err2 = ERR_INVITEONLYCHAN;
305 else if (chptrb->mode.limit && (chptrb->users >= chptrb->mode.limit))
306 err2 = ERR_CHANNELISFULL;
307 else if ((chptrb->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
308 err2 = ERR_NEEDREGGEDNICK;
309 else if ((chptrb->mode.mode & MODE_SSLCHAN) && !IsSSL(sptr))
310 err2 = ERR_SSLCHANNEL;
311 else if (find_ban(sptr, chptrb->banlist))
312 err2 = ERR_BANNEDFROMCHAN;
313 else if (*chptrb->mode.key && (!key || strcmp(key, chptrb->mode.key)))
314 err2 = ERR_BADCHANNELKEY;
316 joinbuf_join(&join, chptrb, flags);
317 del_invite(sptr, chptrb);
318 if (chptrb->topic[0]) {
319 send_reply(sptr, RPL_TOPIC, chptrb->chname, chptrb->topic);
320 send_reply(sptr, RPL_TOPICWHOTIME, chptrb->chname, chptrb->topic_nick, chptrb->topic_time);
322 do_names(sptr, chptrb, NAMES_ALL|NAMES_EON|(((chptrb->mode.mode & MODE_AUDITORIUM) && !(flags & CHFL_CHANOP)) ? NAMES_OPS : 0)); /* send /names list */
328 const char *error = NULL;
329 if (err == ERR_CHANNELISFULL)
330 error = feature_str(FEAT_ERR_CHANNELISFULL);
331 else if (err == ERR_INVITEONLYCHAN)
332 error = feature_str(FEAT_ERR_INVITEONLYCHAN);
333 else if (err == ERR_BANNEDFROMCHAN)
334 error = feature_str(FEAT_ERR_BANNEDFROMCHAN);
335 else if (err == ERR_BADCHANNELKEY)
336 error = feature_str(FEAT_ERR_BADCHANNELKEY);
337 else if (err == ERR_NEEDREGGEDNICK)
338 error = feature_str(FEAT_ERR_NEEDREGGEDNICK);
339 else if (err == ERR_SSLCHANNEL)
340 error = feature_str(FEAT_ERR_SSLCHANNEL);
341 else if (err == ERR_JOINACCESS)
342 error = feature_str(FEAT_ERR_JOINACCESS);
345 send_reply(sptr, err, chptr->chname, error);
347 send_reply(sptr, err, chptr->chname);
351 joinbuf_join(&join, chptr, flags);
352 if (flags & CHFL_CHANOP) {
354 /* Always let the server op him: this is needed on a net with older servers
355 because they 'destruct' channels immediately when they become empty without
356 sending out a DESTRUCT message. As a result, they would always bounce a mode
357 (as HACK(2)) when the user ops himself.
358 (There is also no particularly good reason to have the user op himself.)
360 modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
361 modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
362 chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
363 modebuf_flush(&mbuf);
367 del_invite(sptr, chptr);
369 if (chptr->topic[0]) {
370 send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
371 send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
375 do_names(sptr, chptr, NAMES_ALL|NAMES_EON|(((chptr->mode.mode & MODE_AUDITORIUM) && !(flags & CHFL_CHANOP)) ? NAMES_OPS : 0)); /* send /names list */
378 joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
379 joinbuf_flush(&create);
384 /** Handle a JOIN message from a server connection.
385 * See @ref m_functions for discussion of the arguments.
386 * @param[in] cptr Client that sent us the message.
387 * @param[in] sptr Original source of message.
388 * @param[in] parc Number of arguments.
389 * @param[in] parv Argument vector.
391 int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
393 struct Membership *member;
394 struct Channel *chptr;
397 unsigned int invisible;
405 return protocol_violation(cptr,
406 "%s tried to JOIN %s, duh!",
408 (parc < 2 || *parv[1] == '\0') ? "a channel" :
413 if (parc < 2 || *parv[1] == '\0')
414 return need_more_params(sptr, "JOIN");
416 if (parc > 2 && parv[2])
417 creation = atoi(parv[2]);
418 if (parc > 3 && parv[3])
419 invisible = atoi(parv[3]);
421 joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
423 chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
425 for (name = ircd_strtok(&p, chanlist, ","); name;
426 name = ircd_strtok(&p, 0, ",")) {
428 if (invisible == 1) {
429 flags = CHFL_DEOPPED | CHFL_INVISIBLE;
431 flags = CHFL_DEOPPED;
434 if (IsLocalChannel(name) || !IsChannelName(name))
436 protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
440 if (!(chptr = FindChannel(name)))
442 /* No channel exists, so create one */
443 if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
445 protocol_violation(sptr,"couldn't get channel %s for %s",
446 name,cli_name(sptr));
449 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
451 chptr->creationtime = creation;
452 const struct User* user = cli_user(sptr);
453 if (IsAccount(sptr)) {
454 //chptr->chanowner = user->account;
457 else { /* We have a valid channel? */
458 if ((member = find_member_link(chptr, sptr)))
460 /* It is impossible to get here --Run */
461 if (!IsZombie(member)) /* already on channel */
463 if (invisible == 1) {
464 flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK | CHFL_INVISIBLE);
466 flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
468 remove_user_from_channel(sptr, chptr);
469 chptr = FindChannel(name);
472 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
474 /* Always copy the timestamp when it is older, that is the only way to
475 ensure network-wide synchronization of creation times.
476 We now also copy a creation time that only 1 second younger...
477 this is needed because the timestamp must be incremented
478 by one when someone joins an existing, but empty, channel.
479 However, this is only necessary when the channel is still
480 empty (also here) and when this channel doesn't have +A set.
482 To prevent this from allowing net-rides on the channel, we
483 clear all modes from the channel.
485 (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
486 user in the channel; c1 parts and rejoins, gaining ops.
487 Before s2 sees c1's part, c2 joins the channel and parts
488 immediately. s1 sees c1 part, c1 create, c2 join, c2 part;
489 c2's join resets the timestamp. s2 sees c2 join, c2 part, c1
490 part, c1 create; but since s2 sees the channel as a zannel or
491 non-existent, it does not bounce the create with the newer
494 if (creation && (creation < chptr->creationtime ||
495 (!chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST) && chptr->users == 0))) {
496 struct Membership *member;
499 chptr->creationtime = creation;
500 /* Wipe out the current modes on the channel. */
501 modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3);
503 modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
504 chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
506 if (chptr->mode.limit) {
507 modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
508 chptr->mode.limit = 0;
511 if (chptr->mode.key[0]) {
512 modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
513 chptr->mode.key[0] = '\0';
516 if (chptr->mode.upass[0]) {
517 modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
518 chptr->mode.upass[0] = '\0';
521 if (chptr->mode.apass[0]) {
522 modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
523 chptr->mode.apass[0] = '\0';
526 for (member = chptr->members; member; member = member->next_member)
528 if (IsChanOp(member)) {
529 modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
530 member->status &= ~CHFL_CHANOP;
532 if (HasVoice(member)) {
533 modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member));
534 member->status &= ~CHFL_VOICE;
537 modebuf_flush(&mbuf);
541 joinbuf_join(&join, chptr, flags);
544 joinbuf_flush(&join); /* flush joins... */