Relay detached channel backlog as BouncerServ NOTICE if necessary

Instead of ignoring detached channels wehn replaying backlog,
process them as usual and relay messages as BouncerServ NOTICEs
if necessary. Advance the delivery receipts as if the channel was
attached.

Closes: https://todo.sr.ht/~emersion/soju/98
This commit is contained in:
Simon Ser 2021-04-13 19:11:05 +02:00
parent 76e332b50a
commit a2c207d357
3 changed files with 54 additions and 21 deletions

View file

@ -1030,9 +1030,8 @@ func (dc *downstreamConn) sendTargetBacklog(net *network, target, msgID string)
if dc.caps["draft/chathistory"] || dc.user.msgStore == nil {
return
}
if ch := net.channels.Value(target); ch != nil && ch.Detached {
return
}
ch := net.channels.Value(target)
limit := 4000
targetCM := net.casemap(target)
@ -1056,11 +1055,17 @@ func (dc *downstreamConn) sendTargetBacklog(net *network, target, msgID string)
continue
}
if ch != nil && ch.Detached {
if net.detachedMessageNeedsRelay(ch, msg) {
dc.relayDetachedMessage(net, msg)
}
} else {
if dc.caps["batch"] {
msg.Tags["batch"] = irc.TagValue(batchRef)
}
dc.SendMessage(dc.marshalMessage(msg, net))
}
}
if dc.caps["batch"] {
dc.SendMessage(&irc.Message{
@ -1071,6 +1076,20 @@ func (dc *downstreamConn) sendTargetBacklog(net *network, target, msgID string)
}
}
func (dc *downstreamConn) relayDetachedMessage(net *network, msg *irc.Message) {
if msg.Command != "PRIVMSG" && msg.Command != "NOTICE" {
return
}
sender := msg.Prefix.Name
target, text := msg.Params[0], msg.Params[1]
if net.isHighlight(msg) {
sendServiceNOTICE(dc, fmt.Sprintf("highlight in %v: <%v> %v", dc.marshalEntity(net, target), sender, text))
} else {
sendServiceNOTICE(dc, fmt.Sprintf("message in %v: <%v> %v", dc.marshalEntity(net, target), sender, text))
}
}
func (dc *downstreamConn) runUntilRegistered() error {
for !dc.registered {
msg, err := dc.ReadMessage()

View file

@ -391,10 +391,10 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
ch := uc.network.channels.Value(target)
if ch != nil {
if ch.Detached {
uc.handleDetachedMessage(msg.Prefix.Name, text, ch)
uc.handleDetachedMessage(ch, msg)
}
highlight := msg.Prefix.Name != uc.nick && isHighlight(text, uc.nick)
highlight := uc.network.isHighlight(msg)
if ch.DetachOn == FilterMessage || ch.DetachOn == FilterDefault || (ch.DetachOn == FilterHighlight && highlight) {
uc.updateChannelAutoDetach(target)
}
@ -1437,18 +1437,13 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
return nil
}
func (uc *upstreamConn) handleDetachedMessage(sender string, text string, ch *Channel) {
highlight := sender != uc.nick && isHighlight(text, uc.nick)
if ch.RelayDetached == FilterMessage || ((ch.RelayDetached == FilterHighlight || ch.RelayDetached == FilterDefault) && highlight) {
func (uc *upstreamConn) handleDetachedMessage(ch *Channel, msg *irc.Message) {
if uc.network.detachedMessageNeedsRelay(ch, msg) {
uc.forEachDownstream(func(dc *downstreamConn) {
if highlight {
sendServiceNOTICE(dc, fmt.Sprintf("highlight in %v: <%v> %v", dc.marshalEntity(uc.network, ch.Name), sender, text))
} else {
sendServiceNOTICE(dc, fmt.Sprintf("message in %v: <%v> %v", dc.marshalEntity(uc.network, ch.Name), sender, text))
}
dc.relayDetachedMessage(uc.network, msg)
})
}
if ch.ReattachOn == FilterMessage || (ch.ReattachOn == FilterHighlight && highlight) {
if ch.ReattachOn == FilterMessage || (ch.ReattachOn == FilterHighlight && uc.network.isHighlight(msg)) {
uc.network.attach(ch)
if err := uc.srv.db.StoreChannel(uc.network.ID, ch); err != nil {
uc.logger.Printf("failed to update channel %q: %v", ch.Name, err)
@ -1743,12 +1738,10 @@ func (uc *upstreamConn) produce(target string, msg *irc.Message, origin *downstr
// Don't forward messages if it's a detached channel
ch := uc.network.channels.Value(target)
if ch != nil && ch.Detached {
return
}
detached := ch != nil && ch.Detached
uc.forEachDownstream(func(dc *downstreamConn) {
if dc != origin || dc.caps["echo-message"] {
if !detached && (dc != origin || dc.caps["echo-message"]) {
dc.sendMessageWithID(dc.marshalMessage(msg, uc.network), msgID)
} else {
dc.advanceMessageWithID(msg, msgID)

21
user.go
View file

@ -351,6 +351,27 @@ func (net *network) storeClientDeliveryReceipts(clientName string) {
}
}
func (net *network) isHighlight(msg *irc.Message) bool {
if msg.Command != "PRIVMSG" && msg.Command != "NOTICE" {
return false
}
text := msg.Params[1]
nick := net.Nick
if net.conn != nil {
nick = net.conn.nick
}
// TODO: use case-mapping aware comparison here
return msg.Prefix.Name != nick && isHighlight(text, nick)
}
func (net *network) detachedMessageNeedsRelay(ch *Channel, msg *irc.Message) bool {
highlight := net.isHighlight(msg)
return ch.RelayDetached == FilterMessage || ((ch.RelayDetached == FilterHighlight || ch.RelayDetached == FilterDefault) && highlight)
}
type user struct {
User
srv *Server