diff --git a/irc/channel.go b/irc/channel.go index a39035e8..f8c6e5de 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -545,11 +545,14 @@ func (channel *Channel) ClientStatus(client *Client) (present bool, joinTimeSecs // helper for persisting channel-user modes for always-on clients; // return the channel name and all channel-user modes for a client -func (channel *Channel) alwaysOnStatus(client *Client) (chname string, status alwaysOnChannelStatus) { +func (channel *Channel) alwaysOnStatus(client *Client) (ok bool, chname string, status alwaysOnChannelStatus) { channel.stateMutex.RLock() defer channel.stateMutex.RUnlock() chname = channel.name - data := channel.members[client] + data, ok := channel.members[client] + if !ok { + return + } status.Modes = data.modes.String() status.JoinTime = data.joinTime return diff --git a/irc/client.go b/irc/client.go index 80a60a23..57eb1599 100644 --- a/irc/client.go +++ b/irc/client.go @@ -1803,7 +1803,11 @@ func (client *Client) performWrite(additionalDirtyBits uint) { channels := client.Channels() channelToModes := make(map[string]alwaysOnChannelStatus, len(channels)) for _, channel := range channels { - chname, status := channel.alwaysOnStatus(client) + ok, chname, status := channel.alwaysOnStatus(client) + if !ok { + client.server.logger.Error("internal", "client and channel membership out of sync", chname, client.Nick()) + continue + } channelToModes[chname] = status } client.server.accounts.saveChannels(account, channelToModes)