From 598d9a025b0719da0ea623823ef76153e25898cc Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Fri, 4 Jan 2019 10:03:12 -0500 Subject: [PATCH] review fix: add maxParams for service commands --- irc/chanserv.go | 3 +-- irc/hostserv.go | 4 ++-- irc/services.go | 40 ++++++++++++++++++++++++++-------- irc/utils/fieldsn.go | 52 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 13 deletions(-) create mode 100644 irc/utils/fieldsn.go diff --git a/irc/chanserv.go b/irc/chanserv.go index 9cd5ad42..9b502161 100644 --- a/irc/chanserv.go +++ b/irc/chanserv.go @@ -91,7 +91,6 @@ func csNotice(rb *ResponseBuffer, text string) { func csAmodeHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) { channelName := params[0] - modeChange := strings.Join(params[1:], " ") channel := server.channels.Get(channelName) if channel == nil { @@ -102,7 +101,7 @@ func csAmodeHandler(server *Server, client *Client, command string, params []str return } - modeChanges, unknown := modes.ParseChannelModeChanges(strings.Fields(modeChange)...) + modeChanges, unknown := modes.ParseChannelModeChanges(params[1:]...) var change modes.ModeChange if len(modeChanges) > 1 || len(unknown) > 0 { csNotice(rb, client.t("Invalid mode change")) diff --git a/irc/hostserv.go b/irc/hostserv.go index 3706669a..d66d9c23 100644 --- a/irc/hostserv.go +++ b/irc/hostserv.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "regexp" - "strings" "time" ) @@ -125,6 +124,7 @@ for the rejection.`, capabs: []string{"vhosts"}, enabled: hostservEnabled, minParams: 1, + maxParams: 2, }, } ) @@ -296,7 +296,7 @@ func hsRejectHandler(server *Server, client *Client, command string, params []st var reason string user := params[0] if len(params) > 1 { - reason = strings.Join(params[1:], " ") + reason = params[1] } vhostInfo, err := server.accounts.VHostReject(user, reason) diff --git a/irc/services.go b/irc/services.go index a195e832..5947458e 100644 --- a/irc/services.go +++ b/irc/services.go @@ -11,6 +11,7 @@ import ( "github.com/goshuirc/irc-go/ircfmt" "github.com/goshuirc/irc-go/ircmsg" + "github.com/oragono/oragono/irc/utils" ) // defines an IRC service, e.g., NICKSERV @@ -32,6 +33,7 @@ type serviceCommand struct { authRequired bool enabled func(*Config) bool // is this command enabled in the server config? minParams int + maxParams int // split into at most n params, with last param containing remaining unsplit text } // looks up a command in the table of command definitions for a service, resolving aliases @@ -97,29 +99,49 @@ func serviceCmdHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb return false } - serviceRunCommand(service, server, client, msg.Params, rb) + if len(msg.Params) == 0 { + return false + } + commandName := strings.ToLower(msg.Params[0]) + params := msg.Params[1:] + cmd := lookupServiceCommand(service.Commands, commandName) + // for a maxParams command, join all final parameters together if necessary + if cmd != nil && cmd.maxParams != 0 && cmd.maxParams < len(params) { + newParams := make([]string, cmd.maxParams) + copy(newParams, params[:cmd.maxParams-1]) + newParams[cmd.maxParams-1] = strings.Join(params[cmd.maxParams-1:], " ") + params = newParams + } + serviceRunCommand(service, server, client, cmd, commandName, params, rb) return false } // generic handler for service PRIVMSG, like `/msg NickServ INFO` func servicePrivmsgHandler(service *ircService, server *Server, client *Client, message string, rb *ResponseBuffer) { - serviceRunCommand(service, server, client, strings.Fields(message), rb) -} - -// actually execute a service command -func serviceRunCommand(service *ircService, server *Server, client *Client, params []string, rb *ResponseBuffer) { + params := strings.Fields(message) if len(params) == 0 { return } - commandName := strings.ToLower(params[0]) - params = params[1:] + // look up the service command to see how to parse it + commandName := strings.ToLower(params[0]) + cmd := lookupServiceCommand(service.Commands, commandName) + // reparse if needed + if cmd != nil && cmd.maxParams != 0 { + params = utils.FieldsN(message, cmd.maxParams+1)[1:] + } else { + params = params[1:] + } + serviceRunCommand(service, server, client, cmd, commandName, params, rb) +} + +// actually execute a service command +func serviceRunCommand(service *ircService, server *Server, client *Client, cmd *serviceCommand, commandName string, params []string, rb *ResponseBuffer) { nick := rb.target.Nick() sendNotice := func(notice string) { rb.Add(nil, service.Name, "NOTICE", nick, notice) } - cmd := lookupServiceCommand(service.Commands, commandName) if cmd == nil { sendNotice(fmt.Sprintf("%s /%s HELP", client.t("Unknown command. To see available commands, run"), service.ShortName)) return diff --git a/irc/utils/fieldsn.go b/irc/utils/fieldsn.go new file mode 100644 index 00000000..67a24290 --- /dev/null +++ b/irc/utils/fieldsn.go @@ -0,0 +1,52 @@ +package utils + +// Copyright (c) 2014 Kevin Wallace +// Found here: https://github.com/kevinwallace/fieldsn +// Released under the MIT license +// XXX this implementation treats negative n as "return nil", +// unlike stdlib SplitN and friends, which treat it as "no limit" + +// Original source code below: + +// Package fieldsn implements FieldsN and FieldsFuncN, +// which are conspicuously missing from the strings package. + +import ( + "unicode" +) + +// FieldsN is like strings.Fields, but returns at most n fields, +// and the nth field includes any whitespace at the end of the string. +func FieldsN(s string, n int) []string { + return FieldsFuncN(s, unicode.IsSpace, n) +} + +// FieldsFuncN is like strings.FieldsFunc, but returns at most n fields, +// and the nth field includes any runes at the end of the string normally excluded by f. +func FieldsFuncN(s string, f func(rune) bool, n int) []string { + if n <= 0 { + return nil + } + + a := make([]string, 0, n) + na := 0 + fieldStart := -1 + for i, rune := range s { + if f(rune) { + if fieldStart >= 0 { + a = append(a, s[fieldStart:i]) + na++ + fieldStart = -1 + } + } else if fieldStart == -1 { + fieldStart = i + if na+1 == n { + break + } + } + } + if fieldStart >= 0 { + a = append(a, s[fieldStart:]) + } + return a +}