diff --git a/irc/client.go b/irc/client.go index d4d1813b..70f75194 100644 --- a/irc/client.go +++ b/irc/client.go @@ -235,7 +235,10 @@ func (client *Client) ChangeNickname(nickname string) { } } -func (client *Client) Reply(reply string) { +func (client *Client) Reply(reply string, args ...interface{}) { + if len(args) > 0 { + reply = fmt.Sprintf(reply, args...) + } client.socket.Write(reply) } diff --git a/irc/commands.go b/irc/commands.go index 34f39c95..40431d49 100644 --- a/irc/commands.go +++ b/irc/commands.go @@ -708,21 +708,13 @@ func NewOperCommand(args []string) (editableCommand, error) { type CapCommand struct { BaseCommand - subCommand CapSubCommand - args []string + subCommand CapSubCommand + capabilities CapabilitySet } func (msg *CapCommand) String() string { - return fmt.Sprintf("CAP(subCommand=%s, args=%s)", msg.subCommand, msg.args) -} - -func (msg *CapCommand) Capabilities() []Capability { - strs := strings.Split(msg.args[0], " ") - caps := make([]Capability, len(strs)) - for index, str := range strs { - caps[index] = Capability(str) - } - return caps + return fmt.Sprintf("CAP(subCommand=%s, capabilities=%s)", + msg.subCommand, msg.capabilities) } func NewCapCommand(args []string) (editableCommand, error) { @@ -731,8 +723,15 @@ func NewCapCommand(args []string) (editableCommand, error) { } cmd := &CapCommand{ - subCommand: CapSubCommand(args[0]), - args: args[1:], + subCommand: CapSubCommand(strings.ToUpper(args[0])), + capabilities: make(CapabilitySet), + } + + if len(args) > 1 { + strs := spacesExpr.Split(args[1], -1) + for _, str := range strs { + cmd.capabilities[Capability(str)] = true + } } return cmd, nil } diff --git a/irc/server.go b/irc/server.go index 245dcac2..d3ac14b5 100644 --- a/irc/server.go +++ b/irc/server.go @@ -301,28 +301,36 @@ func (msg *CapCommand) HandleRegServer(server *Server) { switch msg.subCommand { case CAP_LS: client.capState = CapNegotiating - client.Reply(fmt.Sprintf("CAP LS :%d", MultiPrefix)) + client.Reply("CAP LS * :%s", SupportedCapabilities) case CAP_LIST: - client.Reply(fmt.Sprintf("CAP LIST :%s", client.capabilities)) + client.Reply("CAP LIST * :%s", client.capabilities) case CAP_REQ: client.capState = CapNegotiating - caps := msg.Capabilities() - if (len(caps) != 1) && (caps[0] != MultiPrefix) { - client.Reply("CAP NAK :" + msg.args[0]) - return + for capability := range msg.capabilities { + if !SupportedCapabilities[capability] { + client.Reply("CAP NAK * :%s", msg.capabilities) + return + } } - for _, capability := range caps { + for capability := range msg.capabilities { client.capabilities[capability] = true } - client.Reply("CAP ACK :" + msg.args[0]) + client.Reply("CAP ACK * :%s", msg.capabilities) case CAP_CLEAR: + format := strings.TrimRight( + strings.Repeat("%s%s ", len(client.capabilities)), " ") + args := make([]interface{}, len(client.capabilities)) + index := 0 for capability := range client.capabilities { + args[index] = Disable + args[index+1] = capability + index += 2 delete(client.capabilities, capability) } - client.Reply("CAP ACK :") + client.Reply("CAP ACK * :"+format, args...) case CAP_END: client.capState = CapNegotiated diff --git a/irc/types.go b/irc/types.go index ec92a6a4..fc628bdd 100644 --- a/irc/types.go +++ b/irc/types.go @@ -16,6 +16,10 @@ type Capability string type CapModifier rune +func (mod CapModifier) String() string { + return string(mod) +} + type CapState uint type CapabilitySet map[Capability]bool @@ -25,6 +29,7 @@ func (set CapabilitySet) String() string { index := 0 for capability := range set { strs[index] = string(capability) + index += 1 } return strings.Join(strs, " ") }