]> jfr.im git - irc/quakenet/snircd.git/blob - ircd/m_join.c
Merged revisions 59-76 via svnmerge from
[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)) &&
154 GlineIsActive(gline) && !IsAnOper(sptr)) {
155 send_reply(sptr, ERR_BADCHANNAME, name, gline->gl_reason);
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 if (feature_bool(FEAT_AUTOCHANMODES) && feature_str(FEAT_AUTOCHANMODES_LIST) && strlen(feature_str(FEAT_AUTOCHANMODES_LIST)) > 0)
178 SetAutoChanModes(chptr);
179 } else if (find_member_link(chptr, sptr)) {
180 continue; /* already on channel */
181 } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
182 continue;
183 } else {
184 int flags = CHFL_DEOPPED;
185 int err = 0;
186
187 /* Check Apass/Upass -- since we only ever look at a single
188 * "key" per channel now, this hampers brute force attacks. */
189 if (key && !strcmp(key, chptr->mode.apass))
190 flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER;
191 else if (key && !strcmp(key, chptr->mode.upass))
192 flags = CHFL_CHANOP;
193 else if (chptr->users == 0 && !chptr->mode.apass[0]) {
194 /* Joining a zombie channel (zannel): give ops and increment TS. */
195 flags = CHFL_CHANOP;
196 chptr->creationtime++;
197 } else if (IsInvited(sptr, chptr)) {
198 /* Invites bypass these other checks. */
199 } else if (chptr->mode.mode & MODE_INVITEONLY)
200 err = ERR_INVITEONLYCHAN;
201 else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit))
202 err = ERR_CHANNELISFULL;
203 else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
204 err = ERR_NEEDREGGEDNICK;
205 else if (find_ban(sptr, chptr->banlist))
206 err = ERR_BANNEDFROMCHAN;
207 else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)))
208 err = ERR_BADCHANNELKEY;
209
210 /*
211 * ASUKA_X:
212 * Allow XtraOpers to join all channels.
213 * --Bigfoot
214 */
215 if (IsXtraOp(sptr))
216 err = 0;
217
218 /* An oper with WALK_LCHAN privilege can join a local channel
219 * he otherwise could not join by using "OVERRIDE" as the key.
220 * This will generate a HACK(4) notice, but fails if the oper
221 * could normally join the channel. */
222 if (IsLocalChannel(chptr->chname)
223 && HasPriv(sptr, PRIV_WALK_LCHAN)
224 && !(flags & CHFL_CHANOP)
225 && key && !strcmp(key, "OVERRIDE"))
226 {
227 switch (err) {
228 case 0:
229 if (strcmp(chptr->mode.key, "OVERRIDE")
230 && strcmp(chptr->mode.apass, "OVERRIDE")
231 && strcmp(chptr->mode.upass, "OVERRIDE")) {
232 send_reply(sptr, ERR_DONTCHEAT, chptr->chname);
233 continue;
234 }
235 break;
236 case ERR_INVITEONLYCHAN: err = 'i'; break;
237 case ERR_CHANNELISFULL: err = 'l'; break;
238 case ERR_BANNEDFROMCHAN: err = 'b'; break;
239 case ERR_BADCHANNELKEY: err = 'k'; break;
240 case ERR_NEEDREGGEDNICK: err = 'r'; break;
241 default: err = '?'; break;
242 }
243 /* send accountability notice */
244 if (err)
245 sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H "
246 "(overriding +%c)", sptr, chptr, err);
247 err = 0;
248 }
249
250 /* Is there some reason the user may not join? */
251 if (err) {
252 send_reply(sptr, err, chptr->chname);
253 continue;
254 }
255
256 joinbuf_join(&join, chptr, flags);
257 if (flags & CHFL_CHANOP) {
258 struct ModeBuf mbuf;
259 #if 0
260 /* Send a MODE to the other servers. If the user used the A/U pass,
261 * let his server op him, otherwise let him op himself. */
262 modebuf_init(&mbuf, chptr->mode.apass[0] ? &me : sptr, cptr, chptr, MODEBUF_DEST_SERVER);
263 #else
264 /* Always let the server op him: this is needed on a net with older servers
265 because they 'destruct' channels immediately when they become empty without
266 sending out a DESTRUCT message. As a result, they would always bounce a mode
267 (as HACK(2)) when the user ops himself. */
268 modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
269 #endif
270 modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
271 chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
272 modebuf_flush(&mbuf);
273 }
274 }
275
276 del_invite(sptr, chptr);
277
278 if (chptr->topic[0]) {
279 send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
280 send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
281 chptr->topic_time);
282 }
283
284 do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */
285 }
286
287 joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
288 joinbuf_flush(&create);
289
290 return 0;
291 }
292
293 /** Handle a JOIN message from a server connection.
294 * See @ref m_functions for discussion of the arguments.
295 * @param[in] cptr Client that sent us the message.
296 * @param[in] sptr Original source of message.
297 * @param[in] parc Number of arguments.
298 * @param[in] parv Argument vector.
299 */
300 int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
301 {
302 struct Membership *member;
303 struct Channel *chptr;
304 struct JoinBuf join;
305 unsigned int flags;
306 time_t creation = 0;
307 char *p = 0;
308 char *chanlist;
309 char *name;
310
311 if (IsServer(sptr))
312 {
313 return protocol_violation(cptr,
314 "%s tried to JOIN %s, duh!",
315 cli_name(sptr),
316 (parc < 2 || *parv[1] == '\0') ? "a channel" :
317 parv[1]
318 );
319 }
320
321 if (parc < 2 || *parv[1] == '\0')
322 return need_more_params(sptr, "JOIN");
323
324 if (parc > 2 && parv[2])
325 creation = atoi(parv[2]);
326
327 joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
328
329 chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
330
331 for (name = ircd_strtok(&p, chanlist, ","); name;
332 name = ircd_strtok(&p, 0, ",")) {
333
334 flags = CHFL_DEOPPED;
335
336 if (IsLocalChannel(name) || !IsChannelName(name))
337 {
338 protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
339 continue;
340 }
341
342 if (!(chptr = FindChannel(name)))
343 {
344 /* No channel exists, so create one */
345 if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
346 {
347 protocol_violation(sptr,"couldn't get channel %s for %s",
348 name,cli_name(sptr));
349 continue;
350 }
351 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
352
353 chptr->creationtime = creation;
354 }
355 else { /* We have a valid channel? */
356 if ((member = find_member_link(chptr, sptr)))
357 {
358 /* It is impossible to get here --Run */
359 if (!IsZombie(member)) /* already on channel */
360 continue;
361
362 flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
363 remove_user_from_channel(sptr, chptr);
364 chptr = FindChannel(name);
365 }
366 else
367 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
368 /* Always copy the timestamp when it is older, that is the only way to
369 ensure network-wide synchronization of creation times.
370 We now also copy a creation time that only 1 second younger...
371 this is needed because the timestamp must be incremented
372 by one when someone joins an existing, but empty, channel.
373 However, this is only necessary when the channel is still
374 empty (also here) and when this channel doesn't have +A set.
375
376 To prevent this from allowing net-rides on the channel, we
377 clear all modes from the channel.
378
379 (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
380 user in the channel; c1 parts and rejoins, gaining ops.
381 Before s2 sees c1's part, c2 joins the channel and parts
382 immediately. s1 sees c1 part, c1 create, c2 join, c2 part;
383 c2's join resets the timestamp. s2 sees c2 join, c2 part, c1
384 part, c1 create; but since s2 sees the channel as a zannel or
385 non-existent, it does not bounce the create with the newer
386 timestamp.)
387 */
388 if (creation && (creation < chptr->creationtime ||
389 (!chptr->mode.apass[0] && chptr->users == 0))) {
390 struct Membership *member;
391 struct ModeBuf mbuf;
392
393 chptr->creationtime = creation;
394 /* Wipe out the current modes on the channel. */
395 modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3);
396
397 modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
398 chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
399
400 if (chptr->mode.limit) {
401 modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
402 chptr->mode.limit = 0;
403 }
404
405 if (chptr->mode.key[0]) {
406 modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
407 chptr->mode.key[0] = '\0';
408 }
409
410 if (chptr->mode.upass[0]) {
411 modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
412 chptr->mode.upass[0] = '\0';
413 }
414
415 if (chptr->mode.apass[0]) {
416 modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
417 chptr->mode.apass[0] = '\0';
418 }
419
420 for (member = chptr->members; member; member = member->next_member)
421 {
422 if (IsChanOp(member)) {
423 modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
424 member->status &= ~CHFL_CHANOP;
425 }
426 if (HasVoice(member)) {
427 modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member));
428 member->status &= ~CHFL_VOICE;
429 }
430 }
431 modebuf_flush(&mbuf);
432 }
433 }
434
435 joinbuf_join(&join, chptr, flags);
436 }
437
438 joinbuf_flush(&join); /* flush joins... */
439
440 return 0;
441 }