From bab26c7a6f7d208854c873f2ab07ea7e0e88d4ef Mon Sep 17 00:00:00 2001 From: delthas Date: Wed, 25 Mar 2020 23:46:36 +0100 Subject: [PATCH] Add KICK support Downstream and upstream message handling are slightly different because downstreams can send KICK messages with multiple channels or users, while upstreams can only send KICK messages with one channel and one user (according to the RFC). --- downstream.go | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ upstream.go | 37 ++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/downstream.go b/downstream.go index 7946477..676d1f1 100644 --- a/downstream.go +++ b/downstream.go @@ -903,6 +903,62 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error { dc.logger.Printf("failed to delete channel %q in DB: %v", upstreamName, err) } } + case "KICK": + var channelStr, userStr string + if err := parseMessageParams(msg, &channelStr, &userStr); err != nil { + return err + } + + channels := strings.Split(channelStr, ",") + users := strings.Split(userStr, ",") + + var reason string + if len(msg.Params) > 2 { + reason = msg.Params[2] + } + + if len(channels) != 1 && len(channels) != len(users) { + return ircError{&irc.Message{ + Command: irc.ERR_BADCHANMASK, + Params: []string{dc.nick, channelStr, "Bad channel mask"}, + }} + } + + for i, user := range users { + var channel string + if len(channels) == 1 { + channel = channels[0] + } else { + channel = channels[i] + } + + ucChannel, upstreamChannel, err := dc.unmarshalEntity(channel) + if err != nil { + return err + } + + ucUser, upstreamUser, err := dc.unmarshalEntity(user) + if err != nil { + return err + } + + if ucChannel != ucUser { + return ircError{&irc.Message{ + Command: irc.ERR_USERNOTINCHANNEL, + Params: []string{dc.nick, user, channel, "They aren't on that channel"}, + }} + } + uc := ucChannel + + params := []string{upstreamChannel, upstreamUser} + if reason != "" { + params = append(params, reason) + } + uc.SendMessage(&irc.Message{ + Command: "KICK", + Params: params, + }) + } case "MODE": var name string if err := parseMessageParams(msg, &name); err != nil { diff --git a/upstream.go b/upstream.go index 5548e46..3d4cd53 100644 --- a/upstream.go +++ b/upstream.go @@ -582,6 +582,43 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error { }) }) } + case "KICK": + if msg.Prefix == nil { + return fmt.Errorf("expected a prefix") + } + + var channel, user string + if err := parseMessageParams(msg, &channel, &user); err != nil { + return err + } + + var reason string + if len(msg.Params) > 2 { + reason = msg.Params[1] + } + + if user == uc.nick { + uc.logger.Printf("kicked from channel %q by %s", channel, msg.Prefix.Name) + delete(uc.channels, channel) + } else { + ch, err := uc.getChannel(channel) + if err != nil { + return err + } + delete(ch.Members, user) + } + + uc.forEachDownstream(func(dc *downstreamConn) { + params := []string{dc.marshalChannel(uc, channel), dc.marshalNick(uc, user)} + if reason != "" { + params = append(params, reason) + } + dc.SendMessage(&irc.Message{ + Prefix: dc.marshalUserPrefix(uc, msg.Prefix), + Command: "KICK", + Params: params, + }) + }) case "QUIT": if msg.Prefix == nil { return fmt.Errorf("expected a prefix")