[PATCH v2] Fix channel membership prefixes in cached WHO replies
Export this patch
Channel membership prefixes in WHO replies (RPL_WHOREPLY and
RPL_WHOSPCRPL) were cached in the user's flags, which meant those same
prefixes were returned on future cache hits, even though the flags are
channel specific.
Strip the channel membership prefixes from the user's flags before
adding a user to the cache and add the prefixes back when reading from
the cache (using the membership info from the NAMES reply).
---
v2 notes:
- Insert the prefixes after the away status ('H'/'G') and server
indicator operator ('*')
downstream.go | 17 +++++++++++++++++
irc.go | 13 +++++++++++++
upstream.go | 5 +++ --
3 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/downstream.go b/downstream.go
index f48653e..bcc2f55 100644
--- a/downstream.go
+++ b/downstream.go
@@ -2230,6 +2230,23 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
}
if uc.isChannel(mask) {
info.Channel = mask
+
+ // Set channel membership prefixes from cached NAMES reply
+ ch := uc.channels.Get(info.Channel)
+ memberships := ch.Members.Get(info.Nickname)
+ prefixes := formatMemberPrefix(*memberships, dc)
+
+ // Channel membership prefixes are listed after away status ('G'/'H')
+ // and optional server operator indicator ('*')
+ i := strings.IndexFunc(info.Flags, func(f rune) bool {
+ return f != 'G' && f != 'H' && f != '*'
+ })
+
+ if i == -1 {
+ info.Flags += prefixes
+ } else {
+ info.Flags = info.Flags[:i] + prefixes + info.Flags[i:]
+ }
}
dc.SendMessage(ctx, xirc.GenerateWHOXReply(fields, &info))
}
diff --git a/irc.go b/irc.go
index 12732c4..9a7735b 100644
--- a/irc.go
+++ b/irc.go
@@ -194,6 +194,19 @@ func formatMemberPrefix(ms xirc.MembershipSet, dc *downstreamConn) string {
return string(prefixes)
}
+ // Remove channel membership prefixes from flags
+ func stripMemberPrefixes(flags string, uc *upstreamConn) string {
+ return strings.Map(func(r rune) rune {
+ for _, v := range uc.availableMemberships {
+ if byte(r) == v.Prefix {
+ return -1
+ }
+ }
+
+ return r
+ }, flags)
+ }
+
func parseMessageParams(msg *irc.Message, out ...*string) error {
if len(msg.Params) < len(out) {
return newNeedMoreParamsError(msg.Command)
diff --git a/upstream.go b/upstream.go
index 9173c3a..025646e 100644
--- a/upstream.go
+++ b/upstream.go
@@ -1541,7 +1541,7 @@ func (uc *upstreamConn) handleMessage(ctx context.Context, msg *irc.Message) err
Hostname: host,
Server: server,
Nickname: nick,
- Flags: flags,
+ Flags: stripMemberPrefixes(flags, uc),
Realname: realname,
})
}
@@ -1564,13 +1564,14 @@ func (uc *upstreamConn) handleMessage(ctx context.Context, msg *irc.Message) err
if err != nil {
return err
}
+
if uc.shouldCacheUserInfo(info.Nickname) {
uc.cacheUserInfo(info.Nickname, &upstreamUser{
Nickname: info.Nickname,
Username: info.Username,
Hostname: info.Hostname,
Server: info.Server,
- Flags: info.Flags,
+ Flags: stripMemberPrefixes(info.Flags, uc),
Account: info.Account,
Realname: info.Realname,
})
--
2.45.2
Pushed, thanks a lot!
I adjusted slightly the patch to prepend the prefixes when there is no
'H'/'G'/'*' instead of appending, assuming such flags string would only
contain server-specific flags. (This shouldn't really happen in practice
anyways, servers are supposed to always send at least 'H' or 'G'.)