33d857fa9ad67a18893e54539522b235baea8cfa
[ircu2.10.12-pk.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$
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         /* Always let the server op him: this is needed on a net with older servers
250            because they 'destruct' channels immediately when they become empty without
251            sending out a DESTRUCT message. As a result, they would always bounce a mode
252            (as HACK(2)) when the user ops himself.
253            (There is also no particularly good reason to have the user op himself.)
254         */
255         modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
256         modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
257                             chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
258         modebuf_flush(&mbuf);
259       }
260     }
261
262     del_invite(sptr, chptr);
263
264     if (chptr->topic[0]) {
265       send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
266       send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
267                  chptr->topic_time);
268     }
269
270     do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */
271   }
272
273   joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
274   joinbuf_flush(&create);
275
276   return 0;
277 }
278
279 /** Handle a JOIN message from a server connection.
280  * See @ref m_functions for discussion of the arguments.
281  * @param[in] cptr Client that sent us the message.
282  * @param[in] sptr Original source of message.
283  * @param[in] parc Number of arguments.
284  * @param[in] parv Argument vector.
285  */
286 int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
287 {
288   struct Membership *member;
289   struct Channel *chptr;
290   struct JoinBuf join;
291   unsigned int flags;
292   time_t creation = 0;
293   char *p = 0;
294   char *chanlist;
295   char *name;
296
297   if (IsServer(sptr))
298   {
299     return protocol_violation(cptr,
300                               "%s tried to JOIN %s, duh!",
301                               cli_name(sptr),
302                               (parc < 2 || *parv[1] == '\0') ? "a channel" :
303                                                                parv[1]
304                               );
305   }
306
307   if (parc < 2 || *parv[1] == '\0')
308     return need_more_params(sptr, "JOIN");
309
310   if (parc > 2 && parv[2])
311     creation = atoi(parv[2]);
312
313   joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
314
315   chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
316
317   for (name = ircd_strtok(&p, chanlist, ","); name;
318        name = ircd_strtok(&p, 0, ",")) {
319
320     flags = CHFL_DEOPPED;
321
322     if (IsLocalChannel(name) || !IsChannelName(name))
323     {
324       protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
325       continue;
326     }
327
328     if (!(chptr = FindChannel(name)))
329     {
330       /* No channel exists, so create one */
331       if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
332       {
333         protocol_violation(sptr,"couldn't get channel %s for %s",
334                            name,cli_name(sptr));
335         continue;
336       }
337       flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
338
339       chptr->creationtime = creation;
340     }
341     else { /* We have a valid channel? */
342       if ((member = find_member_link(chptr, sptr)))
343       {
344         /* It is impossible to get here --Run */
345         if (!IsZombie(member)) /* already on channel */
346           continue;
347
348         flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
349         remove_user_from_channel(sptr, chptr);
350         chptr = FindChannel(name);
351       }
352       else
353         flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
354       /* Always copy the timestamp when it is older, that is the only way to
355          ensure network-wide synchronization of creation times.
356          We now also copy a creation time that only 1 second younger...
357          this is needed because the timestamp must be incremented
358          by one when someone joins an existing, but empty, channel.
359          However, this is only necessary when the channel is still
360          empty (also here) and when this channel doesn't have +A set.
361
362          To prevent this from allowing net-rides on the channel, we
363          clear all modes from the channel.
364
365          (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
366          user in the channel; c1 parts and rejoins, gaining ops.
367          Before s2 sees c1's part, c2 joins the channel and parts
368          immediately.  s1 sees c1 part, c1 create, c2 join, c2 part;
369          c2's join resets the timestamp.  s2 sees c2 join, c2 part, c1
370          part, c1 create; but since s2 sees the channel as a zannel or
371          non-existent, it does not bounce the create with the newer
372          timestamp.)
373       */
374       if (creation && (creation < chptr->creationtime ||
375                        (!chptr->mode.apass[0] && chptr->users == 0))) {
376         struct Membership *member;
377         struct ModeBuf mbuf;
378
379         chptr->creationtime = creation;
380         /* Wipe out the current modes on the channel. */
381         modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3);
382
383         modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
384         chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
385
386         if (chptr->mode.limit) {
387           modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
388           chptr->mode.limit = 0;
389         }
390
391         if (chptr->mode.key[0]) {
392           modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
393           chptr->mode.key[0] = '\0';
394         }
395
396         if (chptr->mode.upass[0]) {
397           modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
398           chptr->mode.upass[0] = '\0';
399         }
400
401         if (chptr->mode.apass[0]) {
402           modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
403           chptr->mode.apass[0] = '\0';
404         }
405
406         for (member = chptr->members; member; member = member->next_member)
407         {
408           if (IsChanOp(member)) {
409             modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
410             member->status &= ~CHFL_CHANOP;
411           }
412           if (HasVoice(member)) {
413             modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member));
414             member->status &= ~CHFL_VOICE;
415           }
416         }
417         modebuf_flush(&mbuf);
418       }
419     }
420
421     joinbuf_join(&join, chptr, flags);
422   }
423
424   joinbuf_flush(&join); /* flush joins... */
425
426   return 0;
427 }