]> jfr.im git - irc/quakenet/snircd.git/blob - ircd/m_destruct.c
Should be unsigned long for A
[irc/quakenet/snircd.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,v 1.9.2.3 2006/01/03 01:25:50 entrope Exp $
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 }