keep in sync with OGN upstream (SVN-317)
[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         int flags = 0;
162         
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));
167       continue;
168     }
169
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);
174         continue;
175       }
176
177       if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
178         continue;
179
180       /* Try to add the new channel as a recent target for the user. */
181       if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
182         chptr->members = 0;
183         destruct_channel(chptr);
184         continue;
185       }
186
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);
192           }
193       continue;
194     } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
195       continue;
196     } else {
197       flags = CHFL_DEOPPED;
198       int err = 0;
199       int override = 0;
200
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))
206         flags = CHFL_CHANOP;
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. */
209         flags = CHFL_CHANOP;
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 (find_ban(sptr, chptr->banlist))
220         err = ERR_BANNEDFROMCHAN;
221       else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)))
222         err = ERR_BADCHANNELKEY;
223          
224           
225
226       /* An oper with WALK_LCHAN privilege can join a local channel
227        * he otherwise could not join by using "OVERRIDE" as the key.
228        * This will generate a HACK(4) notice, but fails if the oper
229        * could normally join the channel. */
230           if (HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV) && key && !strcmp(key, "INVISIBLE")) {
231            sendto_opmask_butone(0, SNO_HACK4, "INVISIBLE JOIN: %C JOIN %H", sptr, chptr);
232            flags = CHFL_INVISIBLE;
233        err = 0;
234        override = 1;
235           }
236                   
237       if ((HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV))
238           && !(flags & CHFL_CHANOP)
239           && key && !strcmp(key, "OVERRIDE"))
240       {
241         switch (err) {
242         case 0:
243           if (strcmp(chptr->mode.key, "OVERRIDE")
244               && strcmp(chptr->mode.apass, "OVERRIDE")
245               && strcmp(chptr->mode.upass, "OVERRIDE")) {
246             send_reply(sptr, ERR_DONTCHEAT, chptr->chname);
247             continue;
248           }
249           break;
250         case ERR_INVITEONLYCHAN: err = 'i'; break;
251         case ERR_CHANNELISFULL:  err = 'l'; break;
252         case ERR_BANNEDFROMCHAN: err = 'b'; break;
253         case ERR_BADCHANNELKEY:  err = 'k'; break;
254         case ERR_NEEDREGGEDNICK: err = 'r'; break;
255         default: err = '?'; break;
256         }
257         /* send accountability notice */
258         if (err)
259           sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H "
260                                "(overriding +%c)", sptr, chptr, err);
261         err = 0;
262         override = 1;
263       }
264       
265       if(!err && !override && !IsInvited(sptr, chptr) && chptr->mode.access && chptr->mode.access > 0 && chptr->mode.access < 500 && feature_bool(FEAT_CHMODE_A_ENABLE)) {
266         //We have to check the users channel access...
267         struct Client *acptr;
268         if(feature_str(FEAT_CHMODE_A_TARGET) && (acptr = FindUser(feature_str(FEAT_CHMODE_A_TARGET))) && IsNetServ(acptr) && IsService(cli_user(acptr)->server)) {
269             sendcmdto_one(&me, CMD_RELAY, acptr, "%C JA %C %s %i %i", acptr, sptr, chptr->chname, chptr->mode.access, flags);
270             continue; // We can't do anything more here... We have to wait for the response...
271             } else {
272          if(feature_str(FEAT_CHMODE_A_TARGET)) 
273                   send_reply(sptr, ERR_SERVICESDOWN, feature_str(FEAT_CHMODE_A_TARGET));
274          err = ERR_JOINACCESS;
275         }
276       }
277
278       /* Is there some reason the user may not join? */
279           if(err && chptr->mode.altchan && IsChannelName(chptr->mode.altchan) && strIsIrcCh(chptr->mode.altchan)) {
280             char *altchan = chptr->mode.altchan;
281                 
282                 if (!(chptrb = FindChannel(altchan))) {
283           if (((altchan[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(altchan) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
284             //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
285           } else if ((chptrb = get_channel(sptr, altchan, CGT_CREATE))) {
286             joinbuf_join(&create, chptrb, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
287                     do_names(sptr, chptrb, NAMES_ALL|NAMES_EON);
288                   }
289                 } else {
290           if(find_member_link(chptrb, sptr))
291             continue; //we have already joined this channel
292                   //first of all check if we may even join this channel
293                   int err2 = 0;
294                   if (chptrb->users == 0 && !chptrb->mode.apass[0] && !(chptrb->mode.mode & MODE_PERSIST)) {
295             /* Joining a zombie channel (zannel): give ops and increment TS. */
296             flags = CHFL_CHANOP;
297             chptrb->creationtime++;
298           } else if (IsInvited(sptr, chptrb)) {
299              /* Invites and key=OVERRIDE bypass these other checks. */
300           } else if (chptrb->mode.mode & MODE_INVITEONLY)
301             err2 = ERR_INVITEONLYCHAN;
302           else if (chptrb->mode.limit && (chptrb->users >= chptrb->mode.limit))
303             err2 = ERR_CHANNELISFULL;
304           else if ((chptrb->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
305             err2 = ERR_NEEDREGGEDNICK;
306           else if (find_ban(sptr, chptrb->banlist))
307             err2 = ERR_BANNEDFROMCHAN;
308           else if (*chptrb->mode.key && (!key || strcmp(key, chptrb->mode.key)))
309             err2 = ERR_BADCHANNELKEY;
310                   if(!err2) {
311                     joinbuf_join(&join, chptrb, flags);
312                     del_invite(sptr, chptrb);
313             if (chptrb->topic[0]) {
314               send_reply(sptr, RPL_TOPIC, chptrb->chname, chptrb->topic);
315               send_reply(sptr, RPL_TOPICWHOTIME, chptrb->chname, chptrb->topic_nick, chptrb->topic_time);
316             }
317             do_names(sptr, chptrb, NAMES_ALL|NAMES_EON|(((chptrb->mode.mode & MODE_AUDITORIUM) && !(flags & CHFL_CHANOP)) ? NAMES_OPS : 0)); /* send /names list */
318                   }
319             }
320           }
321           
322       if (err) {
323         const char *error = NULL;
324         if (err == ERR_CHANNELISFULL)
325             error = feature_str(FEAT_ERR_CHANNELISFULL);
326         else if (err == ERR_INVITEONLYCHAN)
327             error = feature_str(FEAT_ERR_INVITEONLYCHAN);
328         else if (err == ERR_BANNEDFROMCHAN)
329             error = feature_str(FEAT_ERR_BANNEDFROMCHAN);
330         else if (err == ERR_BADCHANNELKEY)
331             error = feature_str(FEAT_ERR_BADCHANNELKEY);
332         else if (err == ERR_NEEDREGGEDNICK)
333             error = feature_str(FEAT_ERR_NEEDREGGEDNICK);
334         else if (err == ERR_JOINACCESS)
335             error = feature_str(FEAT_ERR_JOINACCESS);
336         
337         if (error)
338             send_reply(sptr, err, chptr->chname, error);
339         else
340             send_reply(sptr, err, chptr->chname);
341         continue;
342       }
343           
344       joinbuf_join(&join, chptr, flags);
345       if (flags & CHFL_CHANOP) {
346         struct ModeBuf mbuf;
347         /* Always let the server op him: this is needed on a net with older servers
348            because they 'destruct' channels immediately when they become empty without
349            sending out a DESTRUCT message. As a result, they would always bounce a mode
350            (as HACK(2)) when the user ops himself.
351            (There is also no particularly good reason to have the user op himself.)
352         */
353         modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
354         modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
355                             chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
356         modebuf_flush(&mbuf);
357       }
358     }
359
360     del_invite(sptr, chptr);
361
362     if (chptr->topic[0]) {
363       send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
364       send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
365                  chptr->topic_time);
366     }
367
368     do_names(sptr, chptr, NAMES_ALL|NAMES_EON|(((chptr->mode.mode & MODE_AUDITORIUM) && !(flags & CHFL_CHANOP)) ? NAMES_OPS : 0)); /* send /names list */
369   }
370
371   joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
372   joinbuf_flush(&create);
373
374   return 0;
375 }
376
377 /** Handle a JOIN message from a server connection.
378  * See @ref m_functions for discussion of the arguments.
379  * @param[in] cptr Client that sent us the message.
380  * @param[in] sptr Original source of message.
381  * @param[in] parc Number of arguments.
382  * @param[in] parv Argument vector.
383  */
384 int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
385 {
386   struct Membership *member;
387   struct Channel *chptr;
388   struct JoinBuf join;
389   unsigned int flags;
390   unsigned int invisible;
391   time_t creation = 0;
392   char *p = 0;
393   char *chanlist;
394   char *name;
395
396   if (IsServer(sptr))
397   {
398     return protocol_violation(cptr,
399                               "%s tried to JOIN %s, duh!",
400                               cli_name(sptr),
401                               (parc < 2 || *parv[1] == '\0') ? "a channel" :
402                                                                parv[1]
403                               );
404   }
405
406   if (parc < 2 || *parv[1] == '\0')
407     return need_more_params(sptr, "JOIN");
408
409   if (parc > 2 && parv[2])
410     creation = atoi(parv[2]);
411   if (parc > 3 && parv[3])
412     invisible = atoi(parv[3]);
413
414   joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
415
416   chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
417
418   for (name = ircd_strtok(&p, chanlist, ","); name;
419        name = ircd_strtok(&p, 0, ",")) {
420
421         if (invisible == 1) {
422     flags = CHFL_DEOPPED | CHFL_INVISIBLE;
423         } else {
424         flags = CHFL_DEOPPED;
425         }
426
427     if (IsLocalChannel(name) || !IsChannelName(name))
428     {
429       protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
430       continue;
431     }
432
433     if (!(chptr = FindChannel(name)))
434     {
435       /* No channel exists, so create one */
436       if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
437       {
438         protocol_violation(sptr,"couldn't get channel %s for %s",
439                            name,cli_name(sptr));
440         continue;
441       }
442       flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
443
444       chptr->creationtime = creation;
445           const struct User* user = cli_user(sptr);
446           if (IsAccount(sptr)) {
447             //chptr->chanowner = user->account;
448           }
449     }
450     else { /* We have a valid channel? */
451       if ((member = find_member_link(chptr, sptr)))
452       {
453         /* It is impossible to get here --Run */
454         if (!IsZombie(member)) /* already on channel */
455           continue;
456         if (invisible == 1) {
457          flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK | CHFL_INVISIBLE);
458         } else {
459          flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
460         }
461         remove_user_from_channel(sptr, chptr);
462         chptr = FindChannel(name);
463       }
464       else {
465                 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
466                 }
467       /* Always copy the timestamp when it is older, that is the only way to
468          ensure network-wide synchronization of creation times.
469          We now also copy a creation time that only 1 second younger...
470          this is needed because the timestamp must be incremented
471          by one when someone joins an existing, but empty, channel.
472          However, this is only necessary when the channel is still
473          empty (also here) and when this channel doesn't have +A set.
474
475          To prevent this from allowing net-rides on the channel, we
476          clear all modes from the channel.
477
478          (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
479          user in the channel; c1 parts and rejoins, gaining ops.
480          Before s2 sees c1's part, c2 joins the channel and parts
481          immediately.  s1 sees c1 part, c1 create, c2 join, c2 part;
482          c2's join resets the timestamp.  s2 sees c2 join, c2 part, c1
483          part, c1 create; but since s2 sees the channel as a zannel or
484          non-existent, it does not bounce the create with the newer
485          timestamp.)
486       */
487       if (creation && (creation < chptr->creationtime ||
488                        (!chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST) && chptr->users == 0))) {
489         struct Membership *member;
490         struct ModeBuf mbuf;
491
492         chptr->creationtime = creation;
493         /* Wipe out the current modes on the channel. */
494         modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3);
495
496         modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
497         chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
498
499         if (chptr->mode.limit) {
500           modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
501           chptr->mode.limit = 0;
502         }
503
504         if (chptr->mode.key[0]) {
505           modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
506           chptr->mode.key[0] = '\0';
507         }
508
509         if (chptr->mode.upass[0]) {
510           modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
511           chptr->mode.upass[0] = '\0';
512         }
513
514         if (chptr->mode.apass[0]) {
515           modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
516           chptr->mode.apass[0] = '\0';
517         }
518
519         for (member = chptr->members; member; member = member->next_member)
520         {
521           if (IsChanOp(member)) {
522             modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
523             member->status &= ~CHFL_CHANOP;
524           }
525           if (HasVoice(member)) {
526             modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member));
527             member->status &= ~CHFL_VOICE;
528           }
529         }
530         modebuf_flush(&mbuf);
531       }
532     }
533
534     joinbuf_join(&join, chptr, flags);
535   }
536
537   joinbuf_flush(&join); /* flush joins... */
538
539   return 0;
540 }