diff --git a/CHANGELOG.md b/CHANGELOG.md index c79cbcf2..5a600d6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ New release of Oragono! ### Fixed * Fixed bug where `HELP` wouldn't correctly display for operators, and added more help topics. +* Fixed display of large `MONITOR` lists. ## [0.3.0] - 2016-10-23 diff --git a/irc/constants.go b/irc/constants.go index fa8af41b..dd0ffe8a 100644 --- a/irc/constants.go +++ b/irc/constants.go @@ -15,4 +15,8 @@ const ( var ( // Ver is the full version of Oragono, used in responses to clients. Ver = fmt.Sprintf("oragono-%s", SemVer) + + // maxLastArgLength is used to simply cap off the final argument when creating general messages where we need to select a limit. + // for instance, in MONITOR lists, RPL_ISUPPORT lists, etc. + maxLastArgLength = 400 ) diff --git a/irc/isupport.go b/irc/isupport.go index 9cffb236..6253f1e5 100644 --- a/irc/isupport.go +++ b/irc/isupport.go @@ -6,7 +6,6 @@ package irc import "fmt" const isupportSupportedString = "are supported by this server" -const maxISupportLength = 400 // Max length of a single ISUPPORT token line // ISupportList holds a list of ISUPPORT tokens type ISupportList struct { @@ -55,7 +54,7 @@ func (il *ISupportList) GetDifference(newil *ISupportList) [][]string { token := fmt.Sprintf("-%s", name) - if len(token)+length <= maxISupportLength { + if len(token)+length <= maxLastArgLength { // account for the space separating tokens if len(cache) > 0 { length++ @@ -64,7 +63,7 @@ func (il *ISupportList) GetDifference(newil *ISupportList) [][]string { length += len(token) } - if len(cache) == 13 || len(token)+length >= maxISupportLength { + if len(cache) == 13 || len(token)+length >= maxLastArgLength { cache = append(cache, isupportSupportedString) replies = append(replies, cache) cache = make([]string, 0) @@ -81,7 +80,7 @@ func (il *ISupportList) GetDifference(newil *ISupportList) [][]string { token := getTokenString(name, value) - if len(token)+length <= maxISupportLength { + if len(token)+length <= maxLastArgLength { // account for the space separating tokens if len(cache) > 0 { length++ @@ -90,7 +89,7 @@ func (il *ISupportList) GetDifference(newil *ISupportList) [][]string { length += len(token) } - if len(cache) == 13 || len(token)+length >= maxISupportLength { + if len(cache) == 13 || len(token)+length >= maxLastArgLength { cache = append(cache, isupportSupportedString) replies = append(replies, cache) cache = make([]string, 0) @@ -115,7 +114,7 @@ func (il *ISupportList) RegenerateCachedReply() { for name, value := range il.Tokens { token := getTokenString(name, value) - if len(token)+length <= maxISupportLength { + if len(token)+length <= maxLastArgLength { // account for the space separating tokens if len(cache) > 0 { length++ @@ -124,7 +123,7 @@ func (il *ISupportList) RegenerateCachedReply() { length += len(token) } - if len(cache) == 13 || len(token)+length >= maxISupportLength { + if len(cache) == 13 || len(token)+length >= maxLastArgLength { cache = append(cache, isupportSupportedString) il.CachedReply = append(il.CachedReply, cache) cache = make([]string, 0) diff --git a/irc/monitor.go b/irc/monitor.go index dfa72582..cfe6450e 100644 --- a/irc/monitor.go +++ b/irc/monitor.go @@ -116,7 +116,7 @@ func monitorAddHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bo targets := strings.Split(msg.Params[1], ",") for len(targets) > 0 { // check name length - if len(targets[0]) < 1 { + if len(targets[0]) < 1 || len(targets[0]) > server.limits.NickLen { targets = targets[1:] continue } @@ -176,7 +176,9 @@ func monitorListHandler(server *Server, client *Client, msg ircmsg.IrcMessage) b monitorList = append(monitorList, name) } - client.Send(nil, server.name, RPL_MONLIST, client.nick, strings.Join(monitorList, ",")) + for _, line := range argsToStrings(maxLastArgLength, monitorList, ",") { + client.Send(nil, server.name, RPL_MONLIST, client.nick, line) + } return false } @@ -195,10 +197,14 @@ func monitorStatusHandler(server *Server, client *Client, msg ircmsg.IrcMessage) } if len(online) > 0 { - client.Send(nil, server.name, RPL_MONONLINE, client.nick, strings.Join(online, ",")) + for _, line := range argsToStrings(maxLastArgLength, online, ",") { + client.Send(nil, server.name, RPL_MONONLINE, client.nick, line) + } } if len(offline) > 0 { - client.Send(nil, server.name, RPL_MONOFFLINE, client.nick, strings.Join(offline, ",")) + for _, line := range argsToStrings(maxLastArgLength, offline, ",") { + client.Send(nil, server.name, RPL_MONOFFLINE, client.nick, line) + } } return false diff --git a/irc/util.go b/irc/util.go new file mode 100644 index 00000000..03f806c2 --- /dev/null +++ b/irc/util.go @@ -0,0 +1,35 @@ +// Copyright (c) 2016- Daniel Oaks +// released under the MIT license + +package irc + +// argsToStrings takes the arguments and splits them into a series of strings, +// each argument separated by delim and each string bounded by maxLength. +func argsToStrings(maxLength int, arguments []string, delim string) []string { + var messages []string + + var buffer string + for { + if len(arguments) < 1 { + break + } + + if len(buffer) > 0 && maxLength < len(buffer)+len(delim)+len(arguments[0]) { + messages = append(messages, buffer) + buffer = "" + continue + } + + if len(buffer) > 1 { + buffer += delim + } + buffer += arguments[0] + arguments = arguments[1:] + } + + if len(buffer) > 0 { + messages = append(messages, buffer) + } + + return messages +}