]>
Commit | Line | Data |
---|---|---|
189935b1 | 1 | /* |
2 | * IRC - Internet Relay Chat, ircd/m_destruct.c | |
37d25209 | 3 | * Copyright (C) 1997, 2005 Carlo Wood. |
189935b1 | 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 | * | |
37d25209 | 22 | * $Id: m_destruct.c,v 1.9.2.3 2006/01/03 01:25:50 entrope Exp $ |
189935b1 | 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) { | |
37d25209 | 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. */ | |
189935b1 | 120 | send_channel_modes(cptr, chptr); |
37d25209 | 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 | ||
189935b1 | 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. */ | |
37d25209 | 193 | if (chptr->destruct_event) |
194 | remove_destruct_event(chptr); | |
189935b1 | 195 | destruct_channel(chptr); |
196 | ||
197 | return 0; | |
198 | } |