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
This commit is contained in:
delthas 2020-05-27 21:48:08 +00:00
parent 85d6b50f07
commit dd583107cd
3 changed files with 59 additions and 10 deletions

View File

@ -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 {

10
irc.go
View File

@ -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

View File

@ -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 {