ircu2.10.12 pk910 fork
[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: m_join.c 1906 2009-02-09 03:39:42Z entrope $
24  */
25
26 #include "config.h"
27
28 #include "channel.h"
29 #include "class.h"
30 #include "client.h"
31 #include "gline.h"
32 #include "hash.h"
33 #include "ircd.h"
34 #include "ircd_chattr.h"
35 #include "ircd_features.h"
36 #include "ircd_log.h"
37 #include "ircd_reply.h"
38 #include "ircd_string.h"
39 #include "list.h"
40 #include "msg.h"
41 #include "numeric.h"
42 #include "numnicks.h"
43 #include "s_conf.h"
44 #include "s_debug.h"
45 #include "s_user.h"
46 #include "send.h"
47 #include "sys.h"
48
49 /* #include <assert.h> -- Now using assert in ircd_log.h */
50 #include <stdlib.h>
51 #include <string.h>
52
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).
59  */
60 static char *
61 last0(struct Client *cptr, struct Client *sptr, char *chanlist)
62 {
63   char *p;
64   int join0 = 0;
65
66   for (p = chanlist; p[0]; p++) /* find last "JOIN 0" */
67     if (p[0] == '0' && (p[1] == ',' || p[1] == '\0')) {
68       if (p[1] == ',')
69         p++;
70       chanlist = p + 1;
71       join0 = 1;
72     } else {
73       while (p[0] != ',' && p[0] != '\0') /* skip past channel name */
74         p++;
75
76       if (!p[0]) /* hit the end */
77         break;
78     }
79
80   if (join0) {
81     struct JoinBuf part;
82     struct Membership *member;
83
84     joinbuf_init(&part, sptr, cptr, JOINBUF_TYPE_PARTALL,
85                  "Left all channels", 0);
86
87     joinbuf_join(&part, 0, 0);
88
89     while ((member = cli_user(sptr)->channel))
90       joinbuf_join(&part, member->channel,
91                    IsZombie(member) ? CHFL_ZOMBIE :
92                    IsDelayedJoin(member) ? CHFL_DELAYED :
93                    0);
94
95     joinbuf_flush(&part);
96   }
97
98   return chanlist;
99 }
100
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.
107  */
108 int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
109 {
110   struct Channel *chptr,*chptrb;
111   struct JoinBuf join;
112   struct JoinBuf create;
113   struct Gline *gline;
114   struct Membership *member;
115   char *p = 0;
116   char *chanlist;
117   char *name;
118   char *keys;
119   unsigned int maxchans;
120   const struct User* user = cli_user(sptr);
121
122   if (parc < 2 || *parv[1] == '\0')
123     return need_more_params(sptr, "JOIN");
124
125   joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
126   joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime());
127
128   chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
129
130   keys = parv[2]; /* remember where keys are */
131
132   for (name = ircd_strtok(&p, chanlist, ","); name;
133        name = ircd_strtok(&p, 0, ",")) {
134     char *key = 0;
135
136     /* If we have any more keys, take the first for this channel. */
137     if (!BadPtr(keys)
138         && (keys = strchr(key = keys, ',')))
139       *keys++ = '\0';
140
141     /* Empty keys are the same as no keys. */
142     if (key && !key[0])
143       key = 0;
144
145     if (!IsChannelName(name) || !strIsIrcCh(name))
146     {
147       /* bad channel name */
148       send_reply(sptr, ERR_NOSUCHCHANNEL, name);
149       continue;
150     }
151
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 */
159     }
160
161     /* BADCHANed channel */
162     if ((gline = gline_find(name, GLINE_BADCHAN)) &&
163         GlineIsActive(gline) && !IsAnOper(sptr)) {
164       send_reply(sptr, ERR_BADCHANNAME, name, GlineReason(gline));
165       continue;
166     }
167
168     if (!(chptr = FindChannel(name))) {
169       if (((name[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS))
170           || strlen(name) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
171         send_reply(sptr, ERR_NOSUCHCHANNEL, name);
172         continue;
173       }
174
175       if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
176         continue;
177
178       /* Try to add the new channel as a recent target for the user. */
179       if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
180         chptr->members = 0;
181         destruct_channel(chptr);
182         continue;
183       }
184
185       joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
186     } else if (member = find_member_link(chptr, sptr)) {
187           if(IsDelayedJoin(member) && IsInvisibleJoin(member)) {
188            ClearInvisibleJoin(member);
189            RevealDelayedJoinIfNeeded(sptr, chptr);
190           }
191       continue;
192     } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
193       continue;
194     } else {
195       int flags = CHFL_DEOPPED;
196       int err = 0;
197       int override = 0;
198
199       /* Check Apass/Upass -- since we only ever look at a single
200        * "key" per channel now, this hampers brute force attacks. */
201       if (key && !strcmp(key, chptr->mode.apass))
202         flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER;
203       else if (key && !strcmp(key, chptr->mode.upass))
204         flags = CHFL_CHANOP;
205       else if (chptr->users == 0 && !chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST)) {
206         /* Joining a zombie channel (zannel): give ops and increment TS. */
207         flags = CHFL_CHANOP;
208         chptr->creationtime++;
209       } else if (IsInvited(sptr, chptr) || (IsXtraOp(sptr) && key && strcmp(key, "OVERRIDE") == 0)) {
210         /* Invites and key=OVERRIDE bypass these other checks. */
211       } else if (chptr->mode.mode & MODE_INVITEONLY)
212         err = ERR_INVITEONLYCHAN;
213       else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit))
214         err = ERR_CHANNELISFULL;
215       else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
216         err = ERR_NEEDREGGEDNICK;
217       else if (find_ban(sptr, chptr->banlist))
218         err = ERR_BANNEDFROMCHAN;
219       else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)))
220         err = ERR_BADCHANNELKEY;
221          
222           
223
224       /* An oper with WALK_LCHAN privilege can join a local channel
225        * he otherwise could not join by using "OVERRIDE" as the key.
226        * This will generate a HACK(4) notice, but fails if the oper
227        * could normally join the channel. */
228           if (HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV) && key && !strcmp(key, "INVISIBLE")) {
229            sendto_opmask_butone(0, SNO_HACK4, "INVISIBLE JOIN: %C JOIN %H", sptr, chptr);
230            flags = CHFL_INVISIBLE;
231        err = 0;
232        override = 1;
233           }
234                   
235       if ((HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV))
236           && !(flags & CHFL_CHANOP)
237           && key && !strcmp(key, "OVERRIDE"))
238       {
239         switch (err) {
240         case 0:
241           if (strcmp(chptr->mode.key, "OVERRIDE")
242               && strcmp(chptr->mode.apass, "OVERRIDE")
243               && strcmp(chptr->mode.upass, "OVERRIDE")) {
244             send_reply(sptr, ERR_DONTCHEAT, chptr->chname);
245             continue;
246           }
247           break;
248         case ERR_INVITEONLYCHAN: err = 'i'; break;
249         case ERR_CHANNELISFULL:  err = 'l'; break;
250         case ERR_BANNEDFROMCHAN: err = 'b'; break;
251         case ERR_BADCHANNELKEY:  err = 'k'; break;
252         case ERR_NEEDREGGEDNICK: err = 'r'; break;
253         default: err = '?'; break;
254         }
255         /* send accountability notice */
256         if (err)
257           sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H "
258                                "(overriding +%c)", sptr, chptr, err);
259         err = 0;
260         override = 1;
261       }
262       
263       if(!err && !override && !IsInvited(sptr, chptr) && chptr->mode.access && chptr->mode.access > 0 && chptr->mode.access < 500 && feature_bool(FEAT_CHMODE_A_ENABLE)) {
264         //We have to check the users channel access...
265         struct Client *acptr;
266         if(feature_str(FEAT_CHMODE_A_TARGET) && (acptr = FindUser(feature_str(FEAT_CHMODE_A_TARGET))) && IsNetServ(acptr) && IsService(cli_user(acptr)->server)) {
267             sendcmdto_one(&me, CMD_RELAY, acptr, "%C JA %C %s %i %i", acptr, sptr, chptr->chname, chptr->mode.access, flags);
268             continue; // We can't do anything more here... We have to wait for the response...
269             } else {
270          if(feature_str(FEAT_CHMODE_A_TARGET)) 
271                   send_reply(sptr, ERR_SERVICESDOWN, feature_str(FEAT_CHMODE_A_TARGET));
272          err = ERR_JOINACCESS;
273         }
274       }
275
276       /* Is there some reason the user may not join? */
277           if(err && chptr->mode.altchan && IsChannelName(chptr->mode.altchan) && strIsIrcCh(chptr->mode.altchan)) {
278             char *altchan = chptr->mode.altchan;
279                 
280                 if (!(chptrb = FindChannel(altchan))) {
281          if (((altchan[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(altchan) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
282           //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
283          } else if ((chptrb = get_channel(sptr, altchan, CGT_CREATE))) {
284            joinbuf_join(&create, chptrb, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
285                    do_names(sptr, chptrb, NAMES_ALL|NAMES_EON);
286                  }
287                 } else {
288                  joinbuf_join(&join, chptrb, flags);
289                  del_invite(sptr, chptrb);
290          if (chptrb->topic[0]) {
291           send_reply(sptr, RPL_TOPIC, chptrb->chname, chptrb->topic);
292           send_reply(sptr, RPL_TOPICWHOTIME, chptrb->chname, chptrb->topic_nick, chptrb->topic_time);
293          }
294          do_names(sptr, chptrb, NAMES_ALL|NAMES_EON); /* send /names list */
295                 }
296           }
297           
298       if (err) {
299         switch(err) {
300           case ERR_NEEDREGGEDNICK:
301             send_reply(sptr, 
302                        ERR_NEEDREGGEDNICK, 
303                        chptr->chname, 
304                        feature_str(FEAT_URLREG));            
305             break;
306           default:
307             send_reply(sptr, err, chptr->chname);
308             break;
309         }
310         continue;
311       }
312           
313       joinbuf_join(&join, chptr, flags);
314       if (flags & CHFL_CHANOP) {
315         struct ModeBuf mbuf;
316         /* Always let the server op him: this is needed on a net with older servers
317            because they 'destruct' channels immediately when they become empty without
318            sending out a DESTRUCT message. As a result, they would always bounce a mode
319            (as HACK(2)) when the user ops himself.
320            (There is also no particularly good reason to have the user op himself.)
321         */
322         modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
323         modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
324                             chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
325         modebuf_flush(&mbuf);
326       }
327     }
328
329     del_invite(sptr, chptr);
330
331     if (chptr->topic[0]) {
332       send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
333       send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
334                  chptr->topic_time);
335     }
336
337     do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */
338   }
339
340   joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
341   joinbuf_flush(&create);
342
343   return 0;
344 }
345
346 /** Handle a JOIN message from a server connection.
347  * See @ref m_functions for discussion of the arguments.
348  * @param[in] cptr Client that sent us the message.
349  * @param[in] sptr Original source of message.
350  * @param[in] parc Number of arguments.
351  * @param[in] parv Argument vector.
352  */
353 int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
354 {
355   struct Membership *member;
356   struct Channel *chptr;
357   struct JoinBuf join;
358   unsigned int flags;
359   unsigned int invisible;
360   time_t creation = 0;
361   char *p = 0;
362   char *chanlist;
363   char *name;
364
365   if (IsServer(sptr))
366   {
367     return protocol_violation(cptr,
368                               "%s tried to JOIN %s, duh!",
369                               cli_name(sptr),
370                               (parc < 2 || *parv[1] == '\0') ? "a channel" :
371                                                                parv[1]
372                               );
373   }
374
375   if (parc < 2 || *parv[1] == '\0')
376     return need_more_params(sptr, "JOIN");
377
378   if (parc > 2 && parv[2])
379     creation = atoi(parv[2]);
380   if (parc > 3 && parv[3])
381     invisible = atoi(parv[3]);
382
383   joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
384
385   chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
386
387   for (name = ircd_strtok(&p, chanlist, ","); name;
388        name = ircd_strtok(&p, 0, ",")) {
389
390         if (invisible == 1) {
391     flags = CHFL_DEOPPED | CHFL_INVISIBLE;
392         } else {
393         flags = CHFL_DEOPPED;
394         }
395
396     if (IsLocalChannel(name) || !IsChannelName(name))
397     {
398       protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
399       continue;
400     }
401
402     if (!(chptr = FindChannel(name)))
403     {
404       /* No channel exists, so create one */
405       if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
406       {
407         protocol_violation(sptr,"couldn't get channel %s for %s",
408                            name,cli_name(sptr));
409         continue;
410       }
411       flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
412
413       chptr->creationtime = creation;
414           const struct User* user = cli_user(sptr);
415           if (IsAccount(sptr)) {
416             //chptr->chanowner = user->account;
417           }
418     }
419     else { /* We have a valid channel? */
420       if ((member = find_member_link(chptr, sptr)))
421       {
422         /* It is impossible to get here --Run */
423         if (!IsZombie(member)) /* already on channel */
424           continue;
425         if (invisible == 1) {
426          flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK | CHFL_INVISIBLE);
427         } else {
428          flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
429         }
430         remove_user_from_channel(sptr, chptr);
431         chptr = FindChannel(name);
432       }
433       else {
434                 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
435                 }
436       /* Always copy the timestamp when it is older, that is the only way to
437          ensure network-wide synchronization of creation times.
438          We now also copy a creation time that only 1 second younger...
439          this is needed because the timestamp must be incremented
440          by one when someone joins an existing, but empty, channel.
441          However, this is only necessary when the channel is still
442          empty (also here) and when this channel doesn't have +A set.
443
444          To prevent this from allowing net-rides on the channel, we
445          clear all modes from the channel.
446
447          (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
448          user in the channel; c1 parts and rejoins, gaining ops.
449          Before s2 sees c1's part, c2 joins the channel and parts
450          immediately.  s1 sees c1 part, c1 create, c2 join, c2 part;
451          c2's join resets the timestamp.  s2 sees c2 join, c2 part, c1
452          part, c1 create; but since s2 sees the channel as a zannel or
453          non-existent, it does not bounce the create with the newer
454          timestamp.)
455       */
456       if (creation && (creation < chptr->creationtime ||
457                        (!chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST) && chptr->users == 0))) {
458         struct Membership *member;
459         struct ModeBuf mbuf;
460
461         chptr->creationtime = creation;
462         /* Wipe out the current modes on the channel. */
463         modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3);
464
465         modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
466         chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
467
468         if (chptr->mode.limit) {
469           modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
470           chptr->mode.limit = 0;
471         }
472
473         if (chptr->mode.key[0]) {
474           modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
475           chptr->mode.key[0] = '\0';
476         }
477
478         if (chptr->mode.upass[0]) {
479           modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
480           chptr->mode.upass[0] = '\0';
481         }
482
483         if (chptr->mode.apass[0]) {
484           modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
485           chptr->mode.apass[0] = '\0';
486         }
487
488         for (member = chptr->members; member; member = member->next_member)
489         {
490           if (IsChanOp(member)) {
491             modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
492             member->status &= ~CHFL_CHANOP;
493           }
494           if (HasVoice(member)) {
495             modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member));
496             member->status &= ~CHFL_VOICE;
497           }
498         }
499         modebuf_flush(&mbuf);
500       }
501     }
502
503     joinbuf_join(&join, chptr, flags);
504   }
505
506   joinbuf_flush(&join); /* flush joins... */
507
508   return 0;
509 }