diff --git a/downstream.go b/downstream.go index b6129d2..4707591 100644 --- a/downstream.go +++ b/downstream.go @@ -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,10 +1055,16 @@ func (dc *downstreamConn) sendTargetBacklog(net *network, target, msgID string) continue } - if dc.caps["batch"] { - msg.Tags["batch"] = irc.TagValue(batchRef) + 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)) } - dc.SendMessage(dc.marshalMessage(msg, net)) } if dc.caps["batch"] { @@ -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() diff --git a/upstream.go b/upstream.go index 8eaee2e..b61fc67 100644 --- a/upstream.go +++ b/upstream.go @@ -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) diff --git a/user.go b/user.go index e2e06ee..ac3facd 100644 --- a/user.go +++ b/user.go @@ -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