+2006-06-18 Michael Poole <mdpoole@troilus.org>
+
+ * ircd/channel.c (modebuf_flush_int): Fix typo about changing
+ oplevels. Send correct channel TS for modes to other servers.
+ (mode_parse): Accept timestamps on modes from users on other
+ servers. If the received timestamp is too large, handle that.
+
+ * ircd/m_create.c (ms_create): Mention the CREATE-during-burst
+ case and handle it.
+
+ * ircd/m_mode.c (ms_mode): Put back HACK(3) when oplevels are off.
+
2006-03-14 Wouter Coekarts <wouter@coekaerts.be>
* ircd/s_err.c (RPL_STATSILINE): Add two %s to the first field.
strptr_i = &remstr_i;
}
- /* if we're changing oplevels we know the oplevel, pass it on */
+ /* if we're changing oplevels and we know the oplevel, pass it on */
if (mbuf->mb_channel->mode.apass[0]
&& (MB_TYPE(mbuf, i) & MODE_CHANOP)
&& MB_OPLEVEL(mbuf, i) < MAXOPLEVEL)
addbuf, remstr, addstr);
} else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
/*
- * If HACK2 was set, we're bouncing; we send the MODE back to the
- * connection we got it from with the senses reversed and a TS of 0;
- * origin is us
+ * If HACK2 was set, we're bouncing; we send the MODE back to
+ * the connection we got it from with the senses reversed and
+ * the proper TS; origin is us
*/
sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
mbuf->mb_channel->creationtime);
} else {
/*
- * We're propagating a normal MODE command to the rest of the network;
- * we send the actual channel TS unless this is a HACK3 or a HACK4
+ * We're propagating a normal (or HACK3 or HACK4) MODE command
+ * to the rest of the network. We send the actual channel TS.
*/
- if (IsServer(mbuf->mb_source) || IsMe(mbuf->mb_source))
- sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
- "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
- rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
- addbuf, remstr, addstr,
- (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
- mbuf->mb_channel->creationtime);
- else
- sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
- "%H %s%s%s%s%s%s", mbuf->mb_channel,
- rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
- addbuf, remstr, addstr);
+ sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
+ "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
+ rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
+ addbuf, remstr, addstr,
+ mbuf->mb_channel->creationtime);
}
}
state.parc--;
/* is it a TS? */
- if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
+ if (IsServer(state.cptr) && !state.parc && IsDigit(*modestr)) {
time_t recv_ts;
if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
if (recv_ts && recv_ts < state.chptr->creationtime)
state.chptr->creationtime = recv_ts; /* respect earlier TS */
+ else if (recv_ts > state.chptr->creationtime) {
+ struct Client *sserv;
+
+ /* Check whether the originating server has fully processed
+ * the burst to it. */
+ sserv = state.cptr;
+ if (!IsServer(sserv))
+ sserv = cli_user(sserv)->server;
+ if (IsBurstOrBurstAck(sserv)) {
+ /* This is a legal but unusual case; the source server
+ * probably just has not processed the BURST for this
+ * channel. It SHOULD wipe out all its modes soon, so
+ * silently ignore the mode change rather than send a
+ * bounce that could desync modes from our side (that
+ * have already been sent).
+ */
+ state.mbuf->mb_add = 0;
+ state.mbuf->mb_rem = 0;
+ state.mbuf->mb_count = 0;
+ return state.args_used;
+ } else {
+ /* Server is desynced; bounce the mode and deop the source
+ * to fix it. */
+ state.mbuf->mb_dest &= ~MODEBUF_DEST_CHANNEL;
+ state.mbuf->mb_dest |= MODEBUF_DEST_BOUNCE | MODEBUF_DEST_HACK2;
+ if (!IsServer(state.cptr))
+ state.mbuf->mb_dest |= MODEBUF_DEST_DEOP;
+ }
+ }
break; /* break out of while loop */
} else if (state.flags & MODE_PARSE_STRICT ||
the fact that it was a zannel. The influence of this on a network
that is completely 2.10.12.03 or higher is neglectable: Normally
a server only sends a CREATE after first sending a DESTRUCT. Thus,
- by receiving a CREATE for a zannel one of two things happened:
+ by receiving a CREATE for a zannel one of three things happened:
1. The DESTRUCT was sent during a net.break; this could mean that
our zannel is at the verge of expiring too, it should have been
destructed. It is correct to copy the newer TS now, all modes
already left within the time span of a message propagation.
The channel will therefore be less than 48 hours old and no
'protection' is necessary.
+ 3. The source server sent the CREATE while linking,
+ before it got the BURST for our zannel. If this
+ happens, we should reset the channel back to the old
+ timestamp. This can be distinguished from case #1 by
+ checking IsBurstOrBurstAck(cli_user(sptr)->server).
*/
!(chptr->users == 0 && !chptr->mode.apass[0]))) {
- modebuf_init(&mbuf, sptr, cptr, chptr,
- (MODEBUF_DEST_SERVER | /* Send mode to server */
- MODEBUF_DEST_HACK2 | /* Send a HACK(2) message */
- MODEBUF_DEST_BOUNCE)); /* And bounce the mode */
-
- modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, MAXOPLEVEL + 1);
-
- modebuf_flush(&mbuf);
-
- badop = 1;
+ if (!IsBurstOrBurstAck(cli_user(sptr)->server)) {
+ modebuf_init(&mbuf, sptr, cptr, chptr,
+ (MODEBUF_DEST_SERVER | /* Send mode to server */
+ MODEBUF_DEST_HACK2 | /* Send a HACK(2) message */
+ MODEBUF_DEST_BOUNCE)); /* And bounce the mode */
+
+ modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, MAXOPLEVEL + 1);
+
+ modebuf_flush(&mbuf);
+
+ badop = 1;
+ } else if (chanTS > chptr->creationtime + 4) {
+ /* If their handling of the BURST will lead to deopping the
+ * user, have the user join without getting ops (if the
+ * server's handling of the BURST keeps their ops, the channel
+ * will use our timestamp).
+ */
+ badop = 1;
+ }
+
+ if (badop)
+ joinbuf_join(&join, chptr, 0);
}
}
else /* Channel doesn't exist: create it */
chptr = get_channel(sptr, name, CGT_CREATE);
- if (!badop) /* Set/correct TS */
+ if (!badop) {
+ /* Set (or correct) our copy of the TS */
chptr->creationtime = chanTS;
-
- joinbuf_join(badop ? &join : &create, chptr,
- (badop ? 0 : CHFL_CHANOP));
+ joinbuf_join(&create, chptr, CHFL_CHANOP);
+ }
}
joinbuf_flush(&join); /* flush out the joins and creates */
#include "client.h"
#include "hash.h"
#include "ircd.h"
+#include "ircd_features.h"
#include "ircd_log.h"
#include "ircd_reply.h"
#include "ircd_string.h"
(MODEBUF_DEST_CHANNEL | /* Send mode to clients */
MODEBUF_DEST_SERVER | /* Send mode to servers */
MODEBUF_DEST_HACK4)); /* Send a HACK(4) message */
+ else if (!feature_bool(FEAT_OPLEVELS))
+ modebuf_init(&mbuf, sptr, cptr, chptr,
+ (MODEBUF_DEST_CHANNEL | /* Send mode to clients */
+ MODEBUF_DEST_SERVER | /* Send mode to servers */
+ MODEBUF_DEST_HACK3)); /* Send a HACK(3) message */
else
/* Servers need to be able to op people who join using the Apass
- * or upass, as well as people joining a zannel, therefore we no
- * longer generate HACK3. */
+ * or upass, as well as people joining a zannel, therefore we do
+ * not generate HACK3 when oplevels are on. */
modebuf_init(&mbuf, sptr, cptr, chptr,
(MODEBUF_DEST_CHANNEL | /* Send mode to clients */
MODEBUF_DEST_SERVER)); /* Send mode to servers */