diff --git a/irc/caps/set.go b/irc/caps/set.go index 31d4c98d..c33f6ecb 100644 --- a/irc/caps/set.go +++ b/irc/caps/set.go @@ -89,12 +89,15 @@ func (s *Set) Empty() bool { return utils.BitsetEmpty(s[:]) } -const maxPayloadLength = 440 +const defaultMaxPayloadLength = 450 // Strings returns all of our enabled capabilities as a slice of strings. -func (s *Set) Strings(version Version, values Values) (result []string) { +func (s *Set) Strings(version Version, values Values, maxLen int) (result []string) { + if maxLen == 0 { + maxLen = defaultMaxPayloadLength + } var t utils.TokenLineBuilder - t.Initialize(maxPayloadLength, " ") + t.Initialize(maxLen, " ") var capab Capability asSlice := s[:] diff --git a/irc/caps/set_test.go b/irc/caps/set_test.go index 7ed909bd..dae983a0 100644 --- a/irc/caps/set_test.go +++ b/irc/caps/set_test.go @@ -47,13 +47,13 @@ func TestSets(t *testing.T) { values := make(Values) values[InviteNotify] = "invitemepls" - actualCap301ValuesString := s1.Strings(Cap301, values) + actualCap301ValuesString := s1.Strings(Cap301, values, 0) expectedCap301ValuesString := []string{"invite-notify userhost-in-names"} if !reflect.DeepEqual(actualCap301ValuesString, expectedCap301ValuesString) { t.Errorf("Generated Cap301 values string [%v] did not match expected values string [%v]", actualCap301ValuesString, expectedCap301ValuesString) } - actualCap302ValuesString := s1.Strings(Cap302, values) + actualCap302ValuesString := s1.Strings(Cap302, values, 0) expectedCap302ValuesString := []string{"invite-notify=invitemepls userhost-in-names"} if !reflect.DeepEqual(actualCap302ValuesString, expectedCap302ValuesString) { t.Errorf("Generated Cap302 values string [%s] did not match expected values string [%s]", actualCap302ValuesString, expectedCap302ValuesString) diff --git a/irc/handlers.go b/irc/handlers.go index e5ac2a5e..6a073b12 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -569,9 +569,14 @@ func capHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo sendCapLines := func(cset *caps.Set, values caps.Values) { version := rb.session.capVersion - capLines := cset.Strings(version, values) - // weechat 1.4 has a bug here where it won't accept the CAP reply unless it contains - // the server.name source: + // we're working around two bugs: + // 1. weechat 1.4 won't accept the CAP reply unless it contains the server.name source + // 2. old versions of Kiwi and The Lounge can't parse multiline CAP LS 302 (#661), + // so try as hard as possible to get the response to fit on one line. + // :server.name CAP * LS * : + // 1 7 4 + maxLen := 510 - 1 - len(server.name) - 7 - len(subCommand) - 4 + capLines := cset.Strings(version, values, maxLen) for i, capStr := range capLines { if version >= caps.Cap302 && i < len(capLines)-1 { rb.Add(nil, server.name, "CAP", details.nick, subCommand, "*", capStr) diff --git a/irc/server.go b/irc/server.go index b9a79536..31b8b24e 100644 --- a/irc/server.go +++ b/irc/server.go @@ -710,17 +710,17 @@ func (server *Server) applyConfig(config *Config, initial bool) (err error) { // updated caps get DEL'd and then NEW'd // so, we can just add updated ones to both removed and added lists here and they'll be correctly handled - server.logger.Debug("server", "Updated Caps", strings.Join(updatedCaps.Strings(caps.Cap301, config.Server.capValues), " ")) + server.logger.Debug("server", "Updated Caps", strings.Join(updatedCaps.Strings(caps.Cap301, config.Server.capValues, 0), " ")) addedCaps.Union(updatedCaps) removedCaps.Union(updatedCaps) if !addedCaps.Empty() || !removedCaps.Empty() { capBurstSessions = server.clients.AllWithCapsNotify() - added[caps.Cap301] = addedCaps.Strings(caps.Cap301, config.Server.capValues) - added[caps.Cap302] = addedCaps.Strings(caps.Cap302, config.Server.capValues) + added[caps.Cap301] = addedCaps.Strings(caps.Cap301, config.Server.capValues, 0) + added[caps.Cap302] = addedCaps.Strings(caps.Cap302, config.Server.capValues, 0) // removed never has values, so we leave it as Cap301 - removed = removedCaps.Strings(caps.Cap301, config.Server.capValues) + removed = removedCaps.Strings(caps.Cap301, config.Server.capValues, 0) } for _, sSession := range capBurstSessions {