diff --git a/irc/client_test.go b/irc/client_test.go index 7cfeaabf..2d1addc1 100644 --- a/irc/client_test.go +++ b/irc/client_test.go @@ -56,3 +56,33 @@ func TestUserMasks(t *testing.T) { t.Error("failure to match") } } + +func TestWhoFields(t *testing.T) { + var w whoxFields + + if w.Has('a') { + t.Error("zero value of whoxFields must be empty") + } + w = w.Add('a') + if !w.Has('a') { + t.Error("failed to set and get") + } + if w.Has('A') { + t.Error("false positive") + } + if w.Has('o') { + t.Error("false positive") + } + w = w.Add('🐬') + if w.Has('🐬') { + t.Error("should not be able to set invalid who field") + } + w = w.Add('o') + if !w.Has('o') { + t.Error("failed to set and get") + } + w = w.Add('z') + if !w.Has('z') { + t.Error("failed to set and get") + } +} diff --git a/irc/handlers.go b/irc/handlers.go index 8616ed3e..028565bf 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -2794,30 +2794,32 @@ func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re return true } -const WhoFieldMinimum = int('a') // lowest rune value -const WhoFieldMaximum = int('z') +type whoxFields uint32 // bitset to hold the WHOX field values, 'a' through 'z' -type WhoFields [WhoFieldMaximum - WhoFieldMinimum + 1]bool +func (fields whoxFields) Add(field rune) (result whoxFields) { + index := int(field) - int('a') + if 0 <= index && index < 26 { + return fields | (1 << index) + } else { + return fields + } +} -func (fields *WhoFields) Set(field rune) bool { - index := int(field) - if WhoFieldMinimum <= index && index <= WhoFieldMaximum { - fields[int(field)-WhoFieldMinimum] = true - return true +func (fields whoxFields) Has(field rune) bool { + index := int(field) - int('a') + if 0 <= index && index < 26 { + return (fields & (1 << index)) != 0 } else { return false } } -func (fields *WhoFields) Has(field rune) bool { - return fields[int(field)-WhoFieldMinimum] -} // rplWhoReply returns the WHO(X) reply between one user and another channel/user. // who format: // [*][~|&|@|%|+][B] : // whox format: // [*][~|&|@|%|+][B] : -func (client *Client) rplWhoReply(channel *Channel, target *Client, rb *ResponseBuffer, isWhox bool, fields WhoFields, whoType string) { +func (client *Client) rplWhoReply(channel *Channel, target *Client, rb *ResponseBuffer, isWhox bool, fields whoxFields, whoType string) { params := []string{client.Nick()} details := target.Details() @@ -2940,9 +2942,9 @@ func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo sFields = strings.ToLower(sFields[:typeIndex]) } } - var fields WhoFields + var fields whoxFields for _, field := range sFields { - fields.Set(field) + fields = fields.Add(field) } //TODO(dan): is this used and would I put this param in the Modern doc?