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 { if dc.caps["draft/chathistory"] || dc.user.msgStore == nil {
return return
} }
if ch := net.channels.Value(target); ch != nil && ch.Detached {
return ch := net.channels.Value(target)
}
limit := 4000 limit := 4000
targetCM := net.casemap(target) targetCM := net.casemap(target)
@ -1056,11 +1055,17 @@ func (dc *downstreamConn) sendTargetBacklog(net *network, target, msgID string)
continue continue
} }
if ch != nil && ch.Detached {
if net.detachedMessageNeedsRelay(ch, msg) {
dc.relayDetachedMessage(net, msg)
}
} else {
if dc.caps["batch"] { if dc.caps["batch"] {
msg.Tags["batch"] = irc.TagValue(batchRef) msg.Tags["batch"] = irc.TagValue(batchRef)
} }
dc.SendMessage(dc.marshalMessage(msg, net)) dc.SendMessage(dc.marshalMessage(msg, net))
} }
}
if dc.caps["batch"] { if dc.caps["batch"] {
dc.SendMessage(&irc.Message{ 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 { func (dc *downstreamConn) runUntilRegistered() error {
for !dc.registered { for !dc.registered {
msg, err := dc.ReadMessage() msg, err := dc.ReadMessage()

View File

@ -391,10 +391,10 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
ch := uc.network.channels.Value(target) ch := uc.network.channels.Value(target)
if ch != nil { if ch != nil {
if ch.Detached { 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) { if ch.DetachOn == FilterMessage || ch.DetachOn == FilterDefault || (ch.DetachOn == FilterHighlight && highlight) {
uc.updateChannelAutoDetach(target) uc.updateChannelAutoDetach(target)
} }
@ -1437,18 +1437,13 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
return nil return nil
} }
func (uc *upstreamConn) handleDetachedMessage(sender string, text string, ch *Channel) { func (uc *upstreamConn) handleDetachedMessage(ch *Channel, msg *irc.Message) {
highlight := sender != uc.nick && isHighlight(text, uc.nick) if uc.network.detachedMessageNeedsRelay(ch, msg) {
if ch.RelayDetached == FilterMessage || ((ch.RelayDetached == FilterHighlight || ch.RelayDetached == FilterDefault) && highlight) {
uc.forEachDownstream(func(dc *downstreamConn) { uc.forEachDownstream(func(dc *downstreamConn) {
if highlight { dc.relayDetachedMessage(uc.network, msg)
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))
}
}) })
} }
if ch.ReattachOn == FilterMessage || (ch.ReattachOn == FilterHighlight && highlight) { if ch.ReattachOn == FilterMessage || (ch.ReattachOn == FilterHighlight && uc.network.isHighlight(msg)) {
uc.network.attach(ch) uc.network.attach(ch)
if err := uc.srv.db.StoreChannel(uc.network.ID, ch); err != nil { if err := uc.srv.db.StoreChannel(uc.network.ID, ch); err != nil {
uc.logger.Printf("failed to update channel %q: %v", ch.Name, err) 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 // Don't forward messages if it's a detached channel
ch := uc.network.channels.Value(target) ch := uc.network.channels.Value(target)
if ch != nil && ch.Detached { detached := ch != nil && ch.Detached
return
}
uc.forEachDownstream(func(dc *downstreamConn) { 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) dc.sendMessageWithID(dc.marshalMessage(msg, uc.network), msgID)
} else { } else {
dc.advanceMessageWithID(msg, msgID) 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 { type user struct {
User User
srv *Server srv *Server