Fix bugs relating to joining zannels for a quick release.
[ircu2.10.12-pk.git] / ircd / m_create.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_create.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 /*
27  * m_functions execute protocol messages on this server:
28  *
29  *    cptr    is always NON-NULL, pointing to a *LOCAL* client
30  *            structure (with an open socket connected!). This
31  *            identifies the physical socket where the message
32  *            originated (or which caused the m_function to be
33  *            executed--some m_functions may call others...).
34  *
35  *    sptr    is the source of the message, defined by the
36  *            prefix part of the message if present. If not
37  *            or prefix not found, then sptr==cptr.
38  *
39  *            (!IsServer(cptr)) => (cptr == sptr), because
40  *            prefixes are taken *only* from servers...
41  *
42  *            (IsServer(cptr))
43  *                    (sptr == cptr) => the message didn't
44  *                    have the prefix.
45  *
46  *                    (sptr != cptr && IsServer(sptr) means
47  *                    the prefix specified servername. (?)
48  *
49  *                    (sptr != cptr && !IsServer(sptr) means
50  *                    that message originated from a remote
51  *                    user (not local).
52  *
53  *            combining
54  *
55  *            (!IsServer(sptr)) means that, sptr can safely
56  *            taken as defining the target structure of the
57  *            message in this server.
58  *
59  *    *Always* true (if 'parse' and others are working correct):
60  *
61  *    1)      sptr->from == cptr  (note: cptr->from == cptr)
62  *
63  *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64  *            *cannot* be a local connection, unless it's
65  *            actually cptr!). [MyConnect(x) should probably
66  *            be defined as (x == x->from) --msa ]
67  *
68  *    parc    number of variable parameter strings (if zero,
69  *            parv is allowed to be NULL)
70  *
71  *    parv    a NULL terminated list of parameter pointers,
72  *
73  *                    parv[0], sender (prefix string), if not present
74  *                            this points to an empty string.
75  *                    parv[1]...parv[parc-1]
76  *                            pointers to additional parameters
77  *                    parv[parc] == NULL, *always*
78  *
79  *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
80  *                    non-NULL pointers.
81  */
82 #include "config.h"
83
84 #include "channel.h"
85 #include "client.h"
86 #include "hash.h"
87 #include "ircd.h"
88 #include "ircd_log.h"
89 #include "ircd_reply.h"
90 #include "ircd_string.h"
91 #include "msg.h"
92 #include "numeric.h"
93 #include "numnicks.h"
94 #include "s_debug.h"
95 #include "s_misc.h"
96 #include "s_user.h"
97 #include "send.h"
98
99 /* #include <assert.h> -- Now using assert in ircd_log.h */
100 #include <stdlib.h>
101 #include <string.h>
102
103 /*
104  * ms_create - server message handler
105  */
106 int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
107 {
108   time_t chanTS; /* channel creation time */
109   char *p; /* strtok state */
110   char *name; /* channel name */
111   struct Channel *chptr; /* channel */
112   struct JoinBuf join; /* join and create buffers */
113   struct JoinBuf create;
114   struct ModeBuf mbuf; /* a mode buffer */
115   int badop; /* a flag */
116
117   if (IsServer(sptr))
118     return protocol_violation(sptr,"%s tried to CREATE a channel", cli_name(sptr));
119
120   /* sanity checks: Only accept CREATE messages from servers */
121   if (parc < 3 || *parv[2] == '\0')
122     return need_more_params(sptr,"CREATE");
123
124   chanTS = atoi(parv[2]);
125
126   /* A create that didn't appear during a burst has that servers idea of
127    * the current time.  Use it for lag calculations.
128    */
129   if (!IsBurstOrBurstAck(sptr) && 0 != chanTS &&
130       MAGIC_REMOTE_JOIN_TS != chanTS)
131     cli_serv(cli_user(sptr)->server)->lag = TStime() - chanTS;
132
133   /* If this server is >1 minute fast, warn */
134   if (TStime() - chanTS<-60)
135   {
136     static time_t rate;
137     sendto_opmask_butone_ratelimited(0, SNO_NETWORK, &rate,
138                                      "Timestamp drift from %C (%is); issuing "
139                                      "SETTIME to correct this",
140                                      cli_user(sptr)->server,
141                                      chanTS - TStime());
142     /* Now issue a SETTIME to resync.  If we're in the wrong, our
143      * (RELIABLE_CLOCK) hub will bounce a SETTIME back to us.
144      */
145     sendcmdto_prio_one(&me, CMD_SETTIME, cli_user(sptr)->server,
146                        "%Tu %C", TStime(), cli_user(sptr)->server);
147   }
148
149   joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
150   joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, chanTS);
151
152   /* For each channel in the comma separated list: */
153   for (name = ircd_strtok(&p, parv[1], ","); name;
154        name = ircd_strtok(&p, 0, ",")) {
155     badop = 0;
156
157     if (IsLocalChannel(name))
158       continue;
159
160     if ((chptr = FindChannel(name)))
161     {
162       /* Is the remote server confused? */
163       if (find_member_link(chptr, sptr)) {
164         protocol_violation(sptr, "%s tried to CREATE a channel already joined", cli_name(sptr));
165         continue;
166       }
167
168       /* Check if we need to bounce a mode */
169       if (TStime() - chanTS > TS_LAG_TIME ||
170           (chptr->creationtime && chanTS > chptr->creationtime &&
171            chptr->creationtime != MAGIC_REMOTE_JOIN_TS &&
172            /* Accept CREATE for zannels. This is only really necessary on a network
173               with servers prior to 2.10.12.02: we just accept their TS and ignore
174               the fact that it was a zannel. The influence of this on a network
175               that is completely 2.10.12.03 or higher is neglectable: Normally
176               a server only sends a CREATE after first sending a DESTRUCT. Thus,
177               by receiving a CREATE for a zannel one of two things happened:
178               1. The DESTRUCT was sent during a net.break; this could mean that
179                  our zannel is at the verge of expiring too, it should have been
180                  destructed. It is correct to copy the newer TS now, all modes
181                  already have been reset, so it will be as if it was destructed
182                  and immediately recreated. In order to avoid desyncs of modes,
183                  we don't accept a CREATE for channels that have +A set.
184               2. The DESTRUCT passed, then someone created the channel on our
185                  side and left it again. In this situation we have a near
186                  simultaneous creation on two servers; the person on our side
187                  already left within the time span of a message propagation.
188                  The channel will therefore be less than 48 hours old and no
189                  'protection' is necessary.
190             */
191            !(chptr->users == 0 && !chptr->mode.apass[0]))) {
192         modebuf_init(&mbuf, sptr, cptr, chptr,
193                      (MODEBUF_DEST_SERVER |  /* Send mode to server */
194                       MODEBUF_DEST_HACK2  |  /* Send a HACK(2) message */
195                       MODEBUF_DEST_BOUNCE)); /* And bounce the mode */
196
197         modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, MAXOPLEVEL + 1);
198
199         modebuf_flush(&mbuf);
200
201         badop = 1;
202       }
203     }
204     else /* Channel doesn't exist: create it */
205       chptr = get_channel(sptr, name, CGT_CREATE);
206
207     if (!badop) /* Set/correct TS */
208       chptr->creationtime = chanTS;
209
210     joinbuf_join(badop ? &join : &create, chptr,
211                  (badop ? 0 : CHFL_CHANOP));
212   }
213
214   joinbuf_flush(&join); /* flush out the joins and creates */
215   joinbuf_flush(&create);
216
217   return 0;
218 }