From e84793d7ee397b5ceb0cbaae7e8ddd36700bd327 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Mon, 22 May 2023 12:29:55 -0400 Subject: [PATCH] fix #2063 In #2058 we introduced two bugs: * A nil dereference when an outside user attempts to speak * Ordinary copy of a modes.ModeSet (which should only be accessed via atomics) This fixes both issues. --- irc/channel.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/irc/channel.go b/irc/channel.go index 258d3568..d8c5606f 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -1228,20 +1228,26 @@ func (channel *Channel) CanSpeak(client *Client) (bool, modes.Mode) { channel.stateMutex.RLock() memberData, hasClient := channel.members[client] channel.stateMutex.RUnlock() - clientModes := memberData.modes + + highestMode := func() modes.Mode { + if !hasClient { + return modes.Mode(0) + } + return memberData.modes.HighestChannelUserMode() + } if !hasClient && channel.flags.HasMode(modes.NoOutside) { // TODO: enforce regular +b bans on -n channels? return false, modes.NoOutside } - if channel.isMuted(client) && clientModes.HighestChannelUserMode() == modes.Mode(0) { + if channel.isMuted(client) && highestMode() == modes.Mode(0) { return false, modes.BanMask } - if channel.flags.HasMode(modes.Moderated) && clientModes.HighestChannelUserMode() == modes.Mode(0) { + if channel.flags.HasMode(modes.Moderated) && highestMode() == modes.Mode(0) { return false, modes.Moderated } if channel.flags.HasMode(modes.RegisteredOnlySpeak) && client.Account() == "" && - clientModes.HighestChannelUserMode() == modes.Mode(0) { + highestMode() == modes.Mode(0) { return false, modes.RegisteredOnlySpeak } return true, modes.Mode('?')