]> jfr.im git - irc/quakenet/snircd.git/blob - ircd/m_join.c
ircu2.10.12.06
[irc/quakenet/snircd.git] / ircd / m_join.c
1 /*
2 * IRC - Internet Relay Chat, ircd/m_join.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
5 *
6 * See file AUTHORS in IRC package for additional names of
7 * the programmers.
8 *
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)
12 * any later version.
13 *
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.
18 *
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.
22 *
23 * $Id: m_join.c,v 1.34.2.8 2006/01/07 00:54:09 entrope Exp $
24 */
25
26 #include "config.h"
27
28 #include "channel.h"
29 #include "client.h"
30 #include "gline.h"
31 #include "hash.h"
32 #include "ircd.h"
33 #include "ircd_chattr.h"
34 #include "ircd_features.h"
35 #include "ircd_log.h"
36 #include "ircd_reply.h"
37 #include "ircd_string.h"
38 #include "msg.h"
39 #include "numeric.h"
40 #include "numnicks.h"
41 #include "s_debug.h"
42 #include "s_user.h"
43 #include "send.h"
44 #include "sys.h"
45
46 /* #include <assert.h> -- Now using assert in ircd_log.h */
47 #include <stdlib.h>
48 #include <string.h>
49
50 /** Searches for and handles a 0 in a join list.
51 * @param[in] cptr Client that sent us the message.
52 * @param[in] sptr Original source of message.
53 * @param[in] chanlist List of channels to join.
54 * @return First token in \a chanlist after the final 0 entry, which
55 * may be its nul terminator (if the final entry is a 0 entry).
56 */
57 static char *
58 last0(struct Client *cptr, struct Client *sptr, char *chanlist)
59 {
60 char *p;
61 int join0 = 0;
62
63 for (p = chanlist; p[0]; p++) /* find last "JOIN 0" */
64 if (p[0] == '0' && (p[1] == ',' || p[1] == '\0')) {
65 if (p[1] == ',')
66 p++;
67 chanlist = p + 1;
68 join0 = 1;
69 } else {
70 while (p[0] != ',' && p[0] != '\0') /* skip past channel name */
71 p++;
72
73 if (!p[0]) /* hit the end */
74 break;
75 }
76
77 if (join0) {
78 struct JoinBuf part;
79 struct Membership *member;
80
81 joinbuf_init(&part, sptr, cptr, JOINBUF_TYPE_PARTALL,
82 "Left all channels", 0);
83
84 joinbuf_join(&part, 0, 0);
85
86 while ((member = cli_user(sptr)->channel))
87 joinbuf_join(&part, member->channel,
88 IsZombie(member) ? CHFL_ZOMBIE :
89 IsDelayedJoin(member) ? CHFL_DELAYED :
90 0);
91
92 joinbuf_flush(&part);
93 }
94
95 return chanlist;
96 }
97
98 /** Handle a JOIN message from a client connection.
99 * See @ref m_functions for discussion of the arguments.
100 * @param[in] cptr Client that sent us the message.
101 * @param[in] sptr Original source of message.
102 * @param[in] parc Number of arguments.
103 * @param[in] parv Argument vector.
104 */
105 int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
106 {
107 struct Channel *chptr;
108 struct JoinBuf join;
109 struct JoinBuf create;
110 struct Gline *gline;
111 char *p = 0;
112 char *chanlist;
113 char *name;
114 char *keys;
115
116 if (parc < 2 || *parv[1] == '\0')
117 return need_more_params(sptr, "JOIN");
118
119 joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
120 joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime());
121
122 chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
123
124 keys = parv[2]; /* remember where keys are */
125
126 for (name = ircd_strtok(&p, chanlist, ","); name;
127 name = ircd_strtok(&p, 0, ",")) {
128 char *key = 0;
129
130 /* If we have any more keys, take the first for this channel. */
131 if (!BadPtr(keys)
132 && (keys = strchr(key = keys, ',')))
133 *keys++ = '\0';
134
135 /* Empty keys are the same as no keys. */
136 if (key && !key[0])
137 key = 0;
138
139 if (!IsChannelName(name) || !strIsIrcCh(name))
140 {
141 /* bad channel name */
142 send_reply(sptr, ERR_NOSUCHCHANNEL, name);
143 continue;
144 }
145
146 if (cli_user(sptr)->joined >= feature_int(FEAT_MAXCHANNELSPERUSER)
147 && !HasPriv(sptr, PRIV_CHAN_LIMIT)) {
148 send_reply(sptr, ERR_TOOMANYCHANNELS, name);
149 break; /* no point processing the other channels */
150 }
151
152 /* BADCHANed channel */
153 if ((gline = gline_find(name, GLINE_BADCHAN | GLINE_EXACT)) &&
154 GlineIsActive(gline) && !IsAnOper(sptr)) {
155 send_reply(sptr, ERR_BANNEDFROMCHAN, name);
156 continue;
157 }
158
159 if (!(chptr = FindChannel(name))) {
160 if (((name[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS))
161 || strlen(name) >= IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
162 send_reply(sptr, ERR_NOSUCHCHANNEL, name);
163 continue;
164 }
165
166 if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
167 continue;
168
169 /* Try to add the new channel as a recent target for the user. */
170 if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
171 chptr->members = 0;
172 destruct_channel(chptr);
173 continue;
174 }
175
176 joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
177 } else if (find_member_link(chptr, sptr)) {
178 continue; /* already on channel */
179 } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
180 continue;
181 } else {
182 int flags = CHFL_DEOPPED;
183 int err = 0;
184
185 /* Check Apass/Upass -- since we only ever look at a single
186 * "key" per channel now, this hampers brute force attacks. */
187 if (key && !strcmp(key, chptr->mode.apass))
188 flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER;
189 else if (key && !strcmp(key, chptr->mode.upass))
190 flags = CHFL_CHANOP;
191 else if (chptr->users == 0 && !chptr->mode.apass[0]) {
192 /* Joining a zombie channel (zannel): give ops and increment TS. */
193 flags = CHFL_CHANOP;
194 chptr->creationtime++;
195 } else if (IsInvited(sptr, chptr)) {
196 /* Invites bypass these other checks. */
197 } else if (chptr->mode.mode & MODE_INVITEONLY)
198 err = ERR_INVITEONLYCHAN;
199 else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit))
200 err = ERR_CHANNELISFULL;
201 else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
202 err = ERR_NEEDREGGEDNICK;
203 else if (find_ban(sptr, chptr->banlist))
204 err = ERR_BANNEDFROMCHAN;
205 else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)))
206 err = ERR_BADCHANNELKEY;
207
208 /* An oper with WALK_LCHAN privilege can join a local channel
209 * he otherwise could not join by using "OVERRIDE" as the key.
210 * This will generate a HACK(4) notice, but fails if the oper
211 * could normally join the channel. */
212 if (IsLocalChannel(chptr->chname)
213 && HasPriv(sptr, PRIV_WALK_LCHAN)
214 && !(flags & CHFL_CHANOP)
215 && key && !strcmp(key, "OVERRIDE"))
216 {
217 switch (err) {
218 case 0:
219 if (strcmp(chptr->mode.key, "OVERRIDE")
220 && strcmp(chptr->mode.apass, "OVERRIDE")
221 && strcmp(chptr->mode.upass, "OVERRIDE")) {
222 send_reply(sptr, ERR_DONTCHEAT, chptr->chname);
223 continue;
224 }
225 break;
226 case ERR_INVITEONLYCHAN: err = 'i'; break;
227 case ERR_CHANNELISFULL: err = 'l'; break;
228 case ERR_BANNEDFROMCHAN: err = 'b'; break;
229 case ERR_BADCHANNELKEY: err = 'k'; break;
230 case ERR_NEEDREGGEDNICK: err = 'r'; break;
231 default: err = '?'; break;
232 }
233 /* send accountability notice */
234 if (err)
235 sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H "
236 "(overriding +%c)", sptr, chptr, err);
237 err = 0;
238 }
239
240 /* Is there some reason the user may not join? */
241 if (err) {
242 send_reply(sptr, err, chptr->chname);
243 continue;
244 }
245
246 joinbuf_join(&join, chptr, flags);
247 if (flags & CHFL_CHANOP) {
248 struct ModeBuf mbuf;
249 #if 0
250 /* Send a MODE to the other servers. If the user used the A/U pass,
251 * let his server op him, otherwise let him op himself. */
252 modebuf_init(&mbuf, chptr->mode.apass[0] ? &me : sptr, cptr, chptr, MODEBUF_DEST_SERVER);
253 #else
254 /* Always let the server op him: this is needed on a net with older servers
255 because they 'destruct' channels immediately when they become empty without
256 sending out a DESTRUCT message. As a result, they would always bounce a mode
257 (as HACK(2)) when the user ops himself. */
258 modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
259 #endif
260 modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
261 chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
262 modebuf_flush(&mbuf);
263 }
264 }
265
266 del_invite(sptr, chptr);
267
268 if (chptr->topic[0]) {
269 send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
270 send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
271 chptr->topic_time);
272 }
273
274 do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */
275 }
276
277 joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
278 joinbuf_flush(&create);
279
280 return 0;
281 }
282
283 /** Handle a JOIN message from a server connection.
284 * See @ref m_functions for discussion of the arguments.
285 * @param[in] cptr Client that sent us the message.
286 * @param[in] sptr Original source of message.
287 * @param[in] parc Number of arguments.
288 * @param[in] parv Argument vector.
289 */
290 int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
291 {
292 struct Membership *member;
293 struct Channel *chptr;
294 struct JoinBuf join;
295 unsigned int flags;
296 time_t creation = 0;
297 char *p = 0;
298 char *chanlist;
299 char *name;
300
301 if (IsServer(sptr))
302 {
303 return protocol_violation(cptr,
304 "%s tried to JOIN %s, duh!",
305 cli_name(sptr),
306 (parc < 2 || *parv[1] == '\0') ? "a channel" :
307 parv[1]
308 );
309 }
310
311 if (parc < 2 || *parv[1] == '\0')
312 return need_more_params(sptr, "JOIN");
313
314 if (parc > 2 && parv[2])
315 creation = atoi(parv[2]);
316
317 joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
318
319 chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
320
321 for (name = ircd_strtok(&p, chanlist, ","); name;
322 name = ircd_strtok(&p, 0, ",")) {
323
324 flags = CHFL_DEOPPED;
325
326 if (IsLocalChannel(name) || !IsChannelName(name))
327 {
328 protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
329 continue;
330 }
331
332 if (!(chptr = FindChannel(name)))
333 {
334 /* No channel exists, so create one */
335 if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
336 {
337 protocol_violation(sptr,"couldn't get channel %s for %s",
338 name,cli_name(sptr));
339 continue;
340 }
341 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
342
343 chptr->creationtime = creation;
344 }
345 else { /* We have a valid channel? */
346 if ((member = find_member_link(chptr, sptr)))
347 {
348 /* It is impossible to get here --Run */
349 if (!IsZombie(member)) /* already on channel */
350 continue;
351
352 flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
353 remove_user_from_channel(sptr, chptr);
354 chptr = FindChannel(name);
355 }
356 else
357 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
358 /* Always copy the timestamp when it is older, that is the only way to
359 ensure network-wide synchronization of creation times.
360 We now also copy a creation time that only 1 second younger...
361 this is needed because the timestamp must be incremented
362 by one when someone joins an existing, but empty, channel.
363 However, this is only necessary when the channel is still
364 empty (also here) and when this channel doesn't have +A set.
365
366 To prevent this from allowing net-rides on the channel, we
367 clear all modes from the channel.
368
369 (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
370 user in the channel; c1 parts and rejoins, gaining ops.
371 Before s2 sees c1's part, c2 joins the channel and parts
372 immediately. s1 sees c1 part, c1 create, c2 join, c2 part;
373 c2's join resets the timestamp. s2 sees c2 join, c2 part, c1
374 part, c1 create; but since s2 sees the channel as a zannel or
375 non-existent, it does not bounce the create with the newer
376 timestamp.)
377 */
378 if (creation && (creation < chptr->creationtime ||
379 (!chptr->mode.apass[0] && chptr->users == 0))) {
380 struct Membership *member;
381 struct ModeBuf mbuf;
382
383 chptr->creationtime = creation;
384 /* Wipe out the current modes on the channel. */
385 modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3);
386
387 modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
388 chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
389
390 if (chptr->mode.limit) {
391 modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
392 chptr->mode.limit = 0;
393 }
394
395 if (chptr->mode.key[0]) {
396 modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
397 chptr->mode.key[0] = '\0';
398 }
399
400 if (chptr->mode.upass[0]) {
401 modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
402 chptr->mode.upass[0] = '\0';
403 }
404
405 if (chptr->mode.apass[0]) {
406 modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
407 chptr->mode.apass[0] = '\0';
408 }
409
410 for (member = chptr->members; member; member = member->next_member)
411 {
412 if (IsChanOp(member)) {
413 modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
414 member->status &= ~CHFL_CHANOP;
415 }
416 if (HasVoice(member)) {
417 modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member));
418 member->status &= ~CHFL_VOICE;
419 }
420 }
421 modebuf_flush(&mbuf);
422 }
423 }
424
425 joinbuf_join(&join, chptr, flags);
426 }
427
428 joinbuf_flush(&join); /* flush joins... */
429
430 return 0;
431 }