commands: Simplify and unify minimum required number of args handling

This commit is contained in:
Daniel Oaks 2016-04-15 15:57:08 +10:00
parent 1bafaa0488
commit 9acdeedec6
2 changed files with 68 additions and 78 deletions

View File

@ -58,6 +58,39 @@ var (
WHOIS: ParseWhoisCommand, WHOIS: ParseWhoisCommand,
WHOWAS: ParseWhoWasCommand, WHOWAS: ParseWhoWasCommand,
} }
commandMinimumArgs = map[StringCode]int{
AWAY: 0,
CAP: 1,
DEBUG: 1,
INVITE: 2,
ISON: 1,
JOIN: 1,
KICK: 2,
KILL: 2,
LIST: 0,
MODE: 1,
MOTD: 0,
NAMES: 0,
NICK: 1,
NOTICE: 2,
ONICK: 2,
OPER: 2,
PART: 1,
PASS: 1,
PING: 1,
PONG: 1,
PRIVMSG: 2,
PROXY: 5,
QUIT: 0,
THEATER: 1,
TIME: 0,
TOPIC: 1,
USER: 4,
VERSION: 0,
WHO: 0,
WHOIS: 1,
WHOWAS: 1,
}
) )
type BaseCommand struct { type BaseCommand struct {
@ -81,13 +114,33 @@ func (command *BaseCommand) SetCode(code StringCode) {
command.code = code command.code = code
} }
type NeedMoreParamsCommand struct {
BaseCommand
code StringCode
}
func ParseNeedMoreParams(code StringCode) *NeedMoreParamsCommand {
return &NeedMoreParamsCommand{
code: code,
}
}
func ParseCommand(line string) (cmd Command, err error) { func ParseCommand(line string) (cmd Command, err error) {
code, args := ParseLine(line) code, args := ParseLine(line)
constructor := parseCommandFuncs[code] constructor := parseCommandFuncs[code]
minArgs := commandMinimumArgs[code]
if constructor == nil { if constructor == nil {
cmd = ParseUnknownCommand(args) cmd = ParseUnknownCommand(args)
} else if len(args) < minArgs {
cmd = ParseNeedMoreParams(code)
} else { } else {
cmd, err = constructor(args) cmd, err = constructor(args)
// if NotEnoughArgsError was returned in the command handler itself
if err == NotEnoughArgsError {
cmd = ParseNeedMoreParams(code)
err = nil
}
} }
if cmd != nil { if cmd != nil {
cmd.SetCode(code) cmd.SetCode(code)
@ -150,9 +203,6 @@ type PingCommand struct {
} }
func ParsePingCommand(args []string) (Command, error) { func ParsePingCommand(args []string) (Command, error) {
if len(args) < 1 {
return nil, NotEnoughArgsError
}
msg := &PingCommand{ msg := &PingCommand{
server: NewName(args[0]), server: NewName(args[0]),
} }
@ -171,9 +221,6 @@ type PongCommand struct {
} }
func ParsePongCommand(args []string) (Command, error) { func ParsePongCommand(args []string) (Command, error) {
if len(args) < 1 {
return nil, NotEnoughArgsError
}
message := &PongCommand{ message := &PongCommand{
server1: NewName(args[0]), server1: NewName(args[0]),
} }
@ -204,9 +251,6 @@ func (cmd *PassCommand) CheckPassword() {
} }
func ParsePassCommand(args []string) (Command, error) { func ParsePassCommand(args []string) (Command, error) {
if len(args) < 1 {
return nil, NotEnoughArgsError
}
return &PassCommand{ return &PassCommand{
password: []byte(args[0]), password: []byte(args[0]),
}, nil }, nil
@ -215,9 +259,6 @@ func ParsePassCommand(args []string) (Command, error) {
// NICK <nickname> // NICK <nickname>
func ParseNickCommand(args []string) (Command, error) { func ParseNickCommand(args []string) (Command, error) {
if len(args) != 1 {
return nil, NotEnoughArgsError
}
return &NickCommand{ return &NickCommand{
nickname: NewName(args[0]), nickname: NewName(args[0]),
}, nil }, nil
@ -255,9 +296,6 @@ func (cmd *RFC2812UserCommand) Flags() []UserMode {
} }
func ParseUserCommand(args []string) (Command, error) { func ParseUserCommand(args []string) (Command, error) {
if len(args) != 4 {
return nil, NotEnoughArgsError
}
mode, err := strconv.ParseUint(args[1], 10, 8) mode, err := strconv.ParseUint(args[1], 10, 8)
if err == nil { if err == nil {
msg := &RFC2812UserCommand{ msg := &RFC2812UserCommand{
@ -314,10 +352,6 @@ func ParseJoinCommand(args []string) (Command, error) {
channels: make(map[Name]Text), channels: make(map[Name]Text),
} }
if len(args) == 0 {
return nil, NotEnoughArgsError
}
if args[0] == "0" { if args[0] == "0" {
msg.zero = true msg.zero = true
return msg, nil return msg, nil
@ -356,9 +390,6 @@ func (cmd *PartCommand) Message() Text {
} }
func ParsePartCommand(args []string) (Command, error) { func ParsePartCommand(args []string) (Command, error) {
if len(args) < 1 {
return nil, NotEnoughArgsError
}
msg := &PartCommand{ msg := &PartCommand{
channels: NewNames(strings.Split(args[0], ",")), channels: NewNames(strings.Split(args[0], ",")),
} }
@ -377,9 +408,6 @@ type PrivMsgCommand struct {
} }
func ParsePrivMsgCommand(args []string) (Command, error) { func ParsePrivMsgCommand(args []string) (Command, error) {
if len(args) < 2 {
return nil, NotEnoughArgsError
}
return &PrivMsgCommand{ return &PrivMsgCommand{
target: NewName(args[0]), target: NewName(args[0]),
message: NewText(args[1]), message: NewText(args[1]),
@ -396,9 +424,6 @@ type TopicCommand struct {
} }
func ParseTopicCommand(args []string) (Command, error) { func ParseTopicCommand(args []string) (Command, error) {
if len(args) < 1 {
return nil, NotEnoughArgsError
}
msg := &TopicCommand{ msg := &TopicCommand{
channel: NewName(args[0]), channel: NewName(args[0]),
} }
@ -579,10 +604,6 @@ func ParseChannelModeCommand(channel Name, args []string) (Command, error) {
} }
func ParseModeCommand(args []string) (Command, error) { func ParseModeCommand(args []string) (Command, error) {
if len(args) == 0 {
return nil, NotEnoughArgsError
}
name := NewName(args[0]) name := NewName(args[0])
if name.IsChannel() { if name.IsChannel() {
return ParseChannelModeCommand(name, args[1:]) return ParseChannelModeCommand(name, args[1:])
@ -599,10 +620,6 @@ type WhoisCommand struct {
// WHOIS [ <target> ] <mask> *( "," <mask> ) // WHOIS [ <target> ] <mask> *( "," <mask> )
func ParseWhoisCommand(args []string) (Command, error) { func ParseWhoisCommand(args []string) (Command, error) {
if len(args) < 1 {
return nil, NotEnoughArgsError
}
var masks string var masks string
var target string var target string
@ -651,10 +668,6 @@ func (msg *OperCommand) LoadPassword(server *Server) {
// OPER <name> <password> // OPER <name> <password>
func ParseOperCommand(args []string) (Command, error) { func ParseOperCommand(args []string) (Command, error) {
if len(args) < 2 {
return nil, NotEnoughArgsError
}
cmd := &OperCommand{ cmd := &OperCommand{
name: NewName(args[0]), name: NewName(args[0]),
} }
@ -669,10 +682,6 @@ type CapCommand struct {
} }
func ParseCapCommand(args []string) (Command, error) { func ParseCapCommand(args []string) (Command, error) {
if len(args) < 1 {
return nil, NotEnoughArgsError
}
cmd := &CapCommand{ cmd := &CapCommand{
subCommand: CapSubCommand(strings.ToUpper(args[0])), subCommand: CapSubCommand(strings.ToUpper(args[0])),
capabilities: make(CapabilitySet), capabilities: make(CapabilitySet),
@ -707,9 +716,6 @@ func NewProxyCommand(hostname Name) *ProxyCommand {
} }
func ParseProxyCommand(args []string) (Command, error) { func ParseProxyCommand(args []string) (Command, error) {
if len(args) < 5 {
return nil, NotEnoughArgsError
}
return &ProxyCommand{ return &ProxyCommand{
net: NewName(args[0]), net: NewName(args[0]),
sourceIP: NewName(args[1]), sourceIP: NewName(args[1]),
@ -741,10 +747,6 @@ type IsOnCommand struct {
} }
func ParseIsOnCommand(args []string) (Command, error) { func ParseIsOnCommand(args []string) (Command, error) {
if len(args) == 0 {
return nil, NotEnoughArgsError
}
return &IsOnCommand{ return &IsOnCommand{
nicks: NewNames(args), nicks: NewNames(args),
}, nil }, nil
@ -770,9 +772,6 @@ type NoticeCommand struct {
} }
func ParseNoticeCommand(args []string) (Command, error) { func ParseNoticeCommand(args []string) (Command, error) {
if len(args) < 2 {
return nil, NotEnoughArgsError
}
return &NoticeCommand{ return &NoticeCommand{
target: NewName(args[0]), target: NewName(args[0]),
message: NewText(args[1]), message: NewText(args[1]),
@ -793,9 +792,6 @@ func (msg *KickCommand) Comment() Text {
} }
func ParseKickCommand(args []string) (Command, error) { func ParseKickCommand(args []string) (Command, error) {
if len(args) < 2 {
return nil, NotEnoughArgsError
}
channels := NewNames(strings.Split(args[0], ",")) channels := NewNames(strings.Split(args[0], ","))
users := NewNames(strings.Split(args[1], ",")) users := NewNames(strings.Split(args[1], ","))
if (len(channels) != len(users)) && (len(users) != 1) { if (len(channels) != len(users)) && (len(users) != 1) {
@ -857,10 +853,6 @@ type DebugCommand struct {
} }
func ParseDebugCommand(args []string) (Command, error) { func ParseDebugCommand(args []string) (Command, error) {
if len(args) == 0 {
return nil, NotEnoughArgsError
}
return &DebugCommand{ return &DebugCommand{
subCommand: NewName(strings.ToUpper(args[0])), subCommand: NewName(strings.ToUpper(args[0])),
}, nil }, nil
@ -886,10 +878,6 @@ type InviteCommand struct {
} }
func ParseInviteCommand(args []string) (Command, error) { func ParseInviteCommand(args []string) (Command, error) {
if len(args) < 2 {
return nil, NotEnoughArgsError
}
return &InviteCommand{ return &InviteCommand{
nickname: NewName(args[0]), nickname: NewName(args[0]),
channel: NewName(args[1]), channel: NewName(args[1]),
@ -897,9 +885,7 @@ func ParseInviteCommand(args []string) (Command, error) {
} }
func ParseTheaterCommand(args []string) (Command, error) { func ParseTheaterCommand(args []string) (Command, error) {
if len(args) < 1 { if upperSubCmd := strings.ToUpper(args[0]); upperSubCmd == "IDENTIFY" && len(args) == 3 {
return nil, NotEnoughArgsError
} else if upperSubCmd := strings.ToUpper(args[0]); upperSubCmd == "IDENTIFY" && len(args) == 3 {
return &TheaterIdentifyCommand{ return &TheaterIdentifyCommand{
channel: NewName(args[1]), channel: NewName(args[1]),
PassCommand: PassCommand{password: []byte(args[2])}, PassCommand: PassCommand{password: []byte(args[2])},
@ -941,9 +927,6 @@ type KillCommand struct {
} }
func ParseKillCommand(args []string) (Command, error) { func ParseKillCommand(args []string) (Command, error) {
if len(args) < 2 {
return nil, NotEnoughArgsError
}
return &KillCommand{ return &KillCommand{
nickname: NewName(args[0]), nickname: NewName(args[0]),
comment: NewText(args[1]), comment: NewText(args[1]),
@ -958,9 +941,6 @@ type WhoWasCommand struct {
} }
func ParseWhoWasCommand(args []string) (Command, error) { func ParseWhoWasCommand(args []string) (Command, error) {
if len(args) < 1 {
return nil, NotEnoughArgsError
}
cmd := &WhoWasCommand{ cmd := &WhoWasCommand{
nicknames: NewNames(strings.Split(args[0], ",")), nicknames: NewNames(strings.Split(args[0], ",")),
} }
@ -974,10 +954,6 @@ func ParseWhoWasCommand(args []string) (Command, error) {
} }
func ParseOperNickCommand(args []string) (Command, error) { func ParseOperNickCommand(args []string) (Command, error) {
if len(args) < 2 {
return nil, NotEnoughArgsError
}
return &OperNickCommand{ return &OperNickCommand{
target: NewName(args[0]), target: NewName(args[0]),
nick: NewName(args[1]), nick: NewName(args[1]),

View File

@ -64,6 +64,14 @@ func NewServer(config *Config) *Server {
theaters: config.Theaters(), theaters: config.Theaters(),
} }
// ensure that there is a minimum number of args specified for every command
for name, _ := range parseCommandFuncs {
_, exists := commandMinimumArgs[name]
if !exists {
log.Fatal("commandMinArgs not found for ", name)
}
}
if config.Server.MOTD != "" { if config.Server.MOTD != "" {
file, err := os.Open(config.Server.MOTD) file, err := os.Open(config.Server.MOTD)
if err == nil { if err == nil {
@ -162,6 +170,12 @@ func (server *Server) loadChannels() {
func (server *Server) processCommand(cmd Command) { func (server *Server) processCommand(cmd Command) {
client := cmd.Client() client := cmd.Client()
numCmd, ok := cmd.(*NeedMoreParamsCommand)
if ok {
client.ErrNeedMoreParams(numCmd.code)
return
}
if !client.registered { if !client.registered {
regCmd, ok := cmd.(RegServerCommand) regCmd, ok := cmd.(RegServerCommand)
if !ok { if !ok {