Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions src/channels.c
Original file line number Diff line number Diff line change
Expand Up @@ -714,8 +714,16 @@ void chan_handle_SJOIN(CSTR source, const int ac, char **av) {

/* Restore the topic if it's a new channel, or if it has been reset, or if someone has just been
kicked by services (AutoKick, Restrict, etc) and ChanServ is alone in the channel. */
if (synched && (newChannel || resetTS || (FlagSet(chan->mode, CMODE_CS) && (chan->userCount == 1))))
restore_topic(chan);
if (synched && (newChannel || resetTS || (FlagSet(chan->mode, CMODE_CS) && (chan->userCount == 1)))) {

/* If this SJOIN is part of a remote server's burst (netsplit heal), defer the topic
restore until burst-end — see issue #1. The subsequent TOPIC message from the
same burst would otherwise trigger a second ChanServ TOPIC send. */
Server *src_server = findserver(source);

if (IS_NULL(src_server) || FlagUnset(src_server->flags, SERVER_FLAG_BURSTING))
restore_topic(chan);
}
}
}
}
Expand Down Expand Up @@ -2481,6 +2489,7 @@ void chan_clear_bans(Channel *chan) {

void chan_handle_TOPIC(const char *source, const int ac, char **av) {
Channel *chan;
BOOL src_bursting = FALSE;

ChannelStats *cs;

Expand Down Expand Up @@ -2522,12 +2531,17 @@ void chan_handle_TOPIC(const char *source, const int ac, char **av) {
/* This is a server topic. We are going to treat server topics just like normal topics
during normal operation for now. */

if (synched == TRUE) {
Server *src_server = findserver(source);

if (IS_NOT_NULL(src_server) && FlagSet(src_server->flags, SERVER_FLAG_BURSTING))
src_bursting = TRUE;

if ((synched == TRUE) && !src_bursting) {

ChannelInfo *ci = chan->ci;

if (IS_NOT_NULL(ci) && FlagSet(ci->flags, CI_TOPICLOCK)) {

/* This is a server topic and channel has topiclock on, block this TOPIC
and replace it with ours (code taken from check_topiclock()) */

Expand All @@ -2547,6 +2561,10 @@ void chan_handle_TOPIC(const char *source, const int ac, char **av) {
return;
}
}

/* If src_bursting: fall through to the normal store path. The topic saved below reflects
the remote server's current topic; we defer the TOPICLOCK override (and record_topic)
to the burst-end pass so only one ChanServ TOPIC is emitted. See issue #1. */
}

TRACE_MAIN();
Expand Down Expand Up @@ -2586,9 +2604,11 @@ void chan_handle_TOPIC(const char *source, const int ac, char **av) {
TRACE_MAIN();

/* If we aren't synched this is a server topic, we save it in the channel struct but wait
for synch_topics() to record it if it is the case. */
for synch_topics() to record it if it is the case. Similarly, when the source server is
still bursting (post-netsplit), defer the record until burst-end to preserve ci->last_topic
against the incoming remote topic. See issue #1. */

if ((synched == TRUE) && IS_NOT_NULL(chan->ci))
if ((synched == TRUE) && !src_bursting && IS_NOT_NULL(chan->ci))
record_topic(chan);
}

Expand Down
6 changes: 6 additions & 0 deletions src/messages.c
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,12 @@ static void m_gnotice(CSTR source, const int ac, char **av) {

RemoveFlag(server->flags, SERVER_FLAG_BURSTING);
LOG_SNOOP(s_Snooper, "Synched with \2%s\2%s [Users: %u]", server->name, FlagSet(server->flags, SERVER_FLAG_UPLINK) ? " [Uplink]" : s_NULL, server->userCount);

/* Reconcile topics now that this server finished bursting. chan_handle_TOPIC and
chan_handle_SJOIN deferred TOPICLOCK/KEEPTOPIC enforcement while BURSTING was set,
so any mismatch between ci->last_topic and chan->topic is resolved here with a
single ChanServ TOPIC per channel. See issue #1. */
synch_topics();
}

burst_servers(server);
Expand Down
Loading