ircu2.10.12 pk910 fork
[ircu2.10.12-pk.git] / ircd / m_destruct.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_destruct.c
3  * Copyright (C) 1997, 2005 Carlo Wood.
4  *
5  * See file AUTHORS in IRC package for additional names of
6  * the programmers.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 1, or (at your option)
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  * $Id: m_destruct.c 1600 2006-01-03 01:25:50Z entrope $
23  */
24
25 #include "config.h"
26
27 #include "client.h"
28 #include "hash.h"
29 #include "ircd.h"
30 #include "ircd_log.h"
31 #include "ircd_reply.h"
32 #include "ircd_string.h"
33 #include "msg.h"
34 #include "numeric.h"
35 #include "numnicks.h"
36 #include "send.h"
37 #include "channel.h"
38 #include "destruct_event.h"
39
40 /* #include <assert.h> -- Now using assert in ircd_log.h */
41 #include <stdlib.h>
42
43 /*
44  * ms_destruct - server message handler
45  *
46  * Added 1997 by Run, actually coded and used since 2002.
47  *
48  * parv[0] = sender prefix
49  * parv[1] = channel channelname
50  * parv[2] = channel time stamp
51  *
52  * This message is intended to destruct _empty_ channels.
53  *
54  * The reason it is needed is to somehow add the notion
55  * "I destructed information" to the networks state
56  * (also messages that are still propagating are part
57  *  of the global state).  Without it the network could
58  * easily be desynced as a result of destructing a channel
59  * on only a part of the network while keeping the modes
60  * and creation time on others.
61  * There are three possible ways a DESTRUCT message is
62  * handled by remote servers:
63  * 1) The channel is empty and has the same timestamp
64  *    as on the message.  Conclusion: The channel has
65  *    not been destructed and recreated in the meantime,
66  *    this means that the normal synchronization rules
67  *    account and we react as if we decided to destruct
68  *    the channel ourselves: we destruct the channel and
69  *    send a DESTRUCT in all directions.
70  * 2) The channel is not empty.  In case we cannot remove
71  *    it and do not propagate the DESTRUCT message. Instead
72  *    a resynchronizing BURST message is sent upstream
73  *    in order to restore the channel on that side (which
74  *    will have a TS younger than the current channel if
75  *    it was recreated and will thus be fully synced, just
76  *    like in the case of a real net-junction).
77  * 3) The channel is empty, but the creation time of the
78  *    channel is older than the timestamp on the message.
79  *    This can happen when there is more than one minute
80  *    lag and remotely a channel was created slightly
81  *    after we created the channel, being abandoned again
82  *    and staying empty for a minute without that our
83  *    CREATE reached that remote server.  The remote server
84  *    then could have generated the DESTRUCT.  In the meantime
85  *    our user also left the channel.  We can ignore the
86  *    destruct because it comes from an 'area' that will
87  *    be overridden by our own CREATE: the state that generated
88  *    this DESTRUCT is 'history'.
89  */
90 int ms_destruct(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
91 {
92   time_t chanTS;                /* Creation time of the channel */
93   struct Channel* chptr;
94
95   assert(0 != cptr);
96   assert(0 != sptr);
97   assert(IsServer(cptr));
98
99   if (parc < 3 || EmptyString(parv[2]))
100     return need_more_params(sptr,"DESTRUCT");
101
102   chanTS = atoi(parv[2]);
103
104   /* Ignore DESTRUCT messages for non-existing channels. */
105   if (!(chptr = FindChannel(parv[1])))
106     return 0;
107
108   /* Ignore DESTRUCT when the channel is older than the
109      timestamp on the message. */
110   if (chanTS > chptr->creationtime)
111     return 0;
112
113   /* Don't pass on DESTRUCT messages for channels that
114      are not empty, but instead send a BURST msg upstream. */
115   if (chptr->users > 0) {
116 #if 0   /* Once all servers are 2.10.12, this can be used too.
117            Until then we have to use CREATE and MODE to
118            get the message accross, because older server do
119            not accept a BURST outside the net.burst. */
120     send_channel_modes(cptr, chptr);
121 #else
122   /* This happens when a JOIN and DESTRUCT crossed, ie:
123
124      server1 ----------------- server2
125         DESTRUCT-->   <-- JOIN,MODE
126
127      Where the JOIN and MODE are the result of joining
128      the zannel before it expired on server2, or in the
129      case of simulateous expiration, a DESTRUCT crossing
130      with another DESTRUCT (that will be ignored) and
131      a CREATE of a user joining right after that:
132
133      server1 ----------------- server2
134         DESTRUCT-->   <-- DESTRUCT <-- CREATE
135      
136      in both cases, when the DESTRUCT arrives on
137      server2 we need to send synchronizing messages
138      upstream (to server1).  Since sending two CREATEs
139      or JOINs for the same user after another is a
140      protocol violation, we first have to send PARTs
141      (we can't send a DESTRUCT because 2.10.11 ignores
142      DESTRUCT messages (just passes them on) and has
143      a bug that causes two JOIN's for the same user to
144      result in that user being on the channel twice). */
145
146     struct Membership *member;
147     struct ModeBuf mbuf;
148     struct Ban *link;
149
150     /* Next, send all PARTs upstream. */
151     for (member = chptr->members; member; member = member->next_member)
152       sendcmdto_one(member->user, CMD_PART, cptr, "%H", chptr);
153
154     /* Next, send JOINs for all members. */
155     for (member = chptr->members; member; member = member->next_member)
156       sendcmdto_one(member->user, CMD_JOIN, cptr, "%H", chptr);
157
158     /* Build MODE strings. We use MODEBUF_DEST_BOUNCE with MODE_DEL to assure
159        that the resulting MODEs are only sent upstream. */
160     modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_SERVER | MODEBUF_DEST_BOUNCE);
161
162     /* Op/voice the users as appropriate. We use MODE_DEL because we fake a bounce. */
163     for (member = chptr->members; member; member = member->next_member)
164     {
165       if (IsChanOp(member))
166         modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
167       if (HasVoice(member))
168         modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, MAXOPLEVEL + 1);
169     }
170
171     /* Send other MODEs. */
172     modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
173     if (*chptr->mode.key)
174       modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
175     if (chptr->mode.limit)
176       modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
177     if (*chptr->mode.upass)
178       modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
179     if (*chptr->mode.apass)
180       modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
181     for (link = chptr->banlist; link; link = link->next)
182       modebuf_mode_string(&mbuf, MODE_DEL | MODE_BAN, link->banstr, 0);
183     modebuf_flush(&mbuf);
184 #endif
185
186     return 0;
187   }
188
189   /* Pass on DESTRUCT message and ALSO bounce it back! */
190   sendcmdto_serv_butone(&me, CMD_DESTRUCT, 0, "%s %Tu", parv[1], chanTS);
191
192   /* Remove the empty channel. */
193   if (chptr->destruct_event)
194     remove_destruct_event(chptr);
195   destruct_channel(chptr);
196
197   return 0;
198 }