From dd583107cd74f96af1c75429f0a914d2e2a5fc32 Mon Sep 17 00:00:00 2001 From: delthas Date: Wed, 27 May 2020 21:48:08 +0000 Subject: [PATCH] Add support for TAGMSG and client message tags Previously we dropped all TAGMSG as well as any client message tag sent from downstream. This adds support for properly forwarding TAGMSG and client message tags from downstreams and upstreams. TAGMSG messages are intentionally not logged, because they are currently typically used for +typing, which can generate a lot of traffic and is only useful for a few seconds after it is sent. git-svn-id: file:///srv/svn/repo/suika/trunk@303 f0ae65fe-ee39-954e-97ec-027ff2717ef4 --- downstream.go | 34 ++++++++++++++++++++++++++++++---- irc.go | 10 ++++++++++ upstream.go | 25 +++++++++++++++++++------ 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/downstream.go b/downstream.go index 47f7af4..d80ced5 100644 --- a/downstream.go +++ b/downstream.go @@ -250,6 +250,9 @@ func (dc *downstreamConn) readMessages(ch chan<- event) error { // This can only called from the user goroutine. func (dc *downstreamConn) SendMessage(msg *irc.Message) { if !dc.caps["message-tags"] { + if msg.Command == "TAGMSG" { + return + } msg = msg.Copy() for name := range msg.Tags { supported := false @@ -274,7 +277,7 @@ func (dc *downstreamConn) marshalMessage(msg *irc.Message, net *network) *irc.Me msg.Prefix = dc.marshalUserPrefix(net, msg.Prefix) switch msg.Command { - case "PRIVMSG", "NOTICE": + case "PRIVMSG", "NOTICE", "TAGMSG": msg.Params[0] = dc.marshalEntity(net, msg.Params[0]) case "NICK": // Nick change for another user @@ -1397,6 +1400,7 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error { if err := parseMessageParams(msg, &targetsStr, &text); err != nil { return err } + tags := copyClientTags(msg.Tags) for _, name := range strings.Split(targetsStr, ",") { if name == serviceNick { @@ -1418,14 +1422,15 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error { unmarshaledText = dc.unmarshalText(uc, text) } uc.SendMessageLabeled(dc.id, &irc.Message{ + Tags: tags, Command: "PRIVMSG", Params: []string{upstreamName, unmarshaledText}, }) + echoTags := tags.Copy() + echoTags["time"] = irc.TagValue(time.Now().UTC().Format(serverTimeLayout)) echoMsg := &irc.Message{ - Tags: irc.Tags{ - "time": irc.TagValue(time.Now().UTC().Format(serverTimeLayout)), - }, + Tags: echoTags, Prefix: &irc.Prefix{ Name: uc.nick, User: uc.username, @@ -1440,6 +1445,7 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error { if err := parseMessageParams(msg, &targetsStr, &text); err != nil { return err } + tags := copyClientTags(msg.Tags) for _, name := range strings.Split(targetsStr, ",") { uc, upstreamName, err := dc.unmarshalEntity(name) @@ -1452,10 +1458,30 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error { unmarshaledText = dc.unmarshalText(uc, text) } uc.SendMessageLabeled(dc.id, &irc.Message{ + Tags: tags, Command: "NOTICE", Params: []string{upstreamName, unmarshaledText}, }) } + case "TAGMSG": + var targetsStr string + if err := parseMessageParams(msg, &targetsStr); err != nil { + return err + } + tags := copyClientTags(msg.Tags) + + for _, name := range strings.Split(targetsStr, ",") { + uc, upstreamName, err := dc.unmarshalEntity(name) + if err != nil { + return err + } + + uc.SendMessageLabeled(dc.id, &irc.Message{ + Tags: tags, + Command: "TAGMSG", + Params: []string{upstreamName}, + }) + } case "INVITE": var user, channel string if err := parseMessageParams(msg, &user, &channel); err != nil { diff --git a/irc.go b/irc.go index 50a22c1..8fae660 100644 --- a/irc.go +++ b/irc.go @@ -274,6 +274,16 @@ func parseMessageParams(msg *irc.Message, out ...*string) error { return nil } +func copyClientTags(tags irc.Tags) irc.Tags { + t := make(irc.Tags, len(tags)) + for k, v := range tags { + if strings.HasPrefix(k, "+") { + t[k] = v + } + } + return t +} + type batch struct { Type string Params []string diff --git a/upstream.go b/upstream.go index 1ea282f..60f75fc 100644 --- a/upstream.go +++ b/upstream.go @@ -320,14 +320,20 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error { Params: msg.Params, }) return nil - case "NOTICE", "PRIVMSG": + case "NOTICE", "PRIVMSG", "TAGMSG": if msg.Prefix == nil { return fmt.Errorf("expected a prefix") } var entity, text string - if err := parseMessageParams(msg, &entity, &text); err != nil { - return err + if msg.Command != "TAGMSG" { + if err := parseMessageParams(msg, &entity, &text); err != nil { + return err + } + } else { + if err := parseMessageParams(msg, &entity); err != nil { + return err + } } if msg.Prefix.Name == serviceNick { @@ -341,7 +347,7 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error { if msg.Prefix.User == "" && msg.Prefix.Host == "" { // server message uc.produce("", msg, nil) - } else { // regular user NOTICE or PRIVMSG + } else { // regular user message target := entity if target == uc.nick { target = msg.Prefix.Name @@ -1274,8 +1280,6 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error { }) }) } - case "TAGMSG": - // TODO: relay to downstream connections that accept message-tags case "ACK": // Ignore case irc.RPL_NOWAWAY, irc.RPL_UNAWAY: @@ -1487,6 +1491,15 @@ func (uc *upstreamConn) readMessages(ch chan<- event) error { return nil } +func (uc *upstreamConn) SendMessage(msg *irc.Message) { + if !uc.caps["message-tags"] { + msg = msg.Copy() + msg.Tags = nil + } + + uc.conn.SendMessage(msg) +} + func (uc *upstreamConn) SendMessageLabeled(downstreamID uint64, msg *irc.Message) { if uc.caps["labeled-response"] { if msg.Tags == nil {