소스 검색

Add config option to bridge cross-room replies

Tulir Asokan 2 년 전
부모
커밋
6df2ff7259
6개의 변경된 파일47개의 추가작업 그리고 9개의 파일을 삭제
  1. 1 0
      config/bridge.go
  2. 1 0
      config/upgrade.go
  3. 2 0
      example-config.yaml
  4. 2 2
      go.mod
  5. 4 4
      go.sum
  6. 37 3
      portal.go

+ 1 - 0
config/bridge.go

@@ -118,6 +118,7 @@ type BridgeConfig struct {
 	CaptionInMessage      bool   `yaml:"caption_in_message"`
 	ExtEvPolls            bool   `yaml:"extev_polls"`
 	SendWhatsAppEdits     bool   `yaml:"send_whatsapp_edits"`
+	CrossRoomReplies      bool   `yaml:"cross_room_replies"`
 
 	MessageHandlingTimeout struct {
 		ErrorAfterStr string `yaml:"error_after"`

+ 1 - 0
config/upgrade.go

@@ -107,6 +107,7 @@ func DoUpgrade(helper *up.Helper) {
 		helper.Copy(up.Bool, "bridge", "extev_polls")
 	}
 	helper.Copy(up.Bool, "bridge", "send_whatsapp_edits")
+	helper.Copy(up.Bool, "bridge", "cross_room_replies")
 	helper.Copy(up.Str|up.Null, "bridge", "message_handling_timeout", "error_after")
 	helper.Copy(up.Str|up.Null, "bridge", "message_handling_timeout", "deadline")
 

+ 2 - 0
example-config.yaml

@@ -312,6 +312,8 @@ bridge:
     # Should Matrix edits be bridged to WhatsApp edits?
     # Official WhatsApp clients don't render edits yet, but once they do, the bridge should work with them right away.
     send_whatsapp_edits: false
+    # Should cross-chat replies from WhatsApp be bridged? Most servers and clients don't support this.
+    cross_room_replies: false
     # Maximum time for handling Matrix events. Duration strings formatted for https://pkg.go.dev/time#ParseDuration
     # Null means there's no enforced timeout.
     message_handling_timeout:

+ 2 - 2
go.mod

@@ -16,7 +16,7 @@ require (
 	golang.org/x/net v0.6.0
 	google.golang.org/protobuf v1.28.1
 	maunium.net/go/maulogger/v2 v2.4.1
-	maunium.net/go/mautrix v0.15.0-beta.2
+	maunium.net/go/mautrix v0.15.0-beta.2.0.20230308151314-83fcdcf30f00
 )
 
 require (
@@ -37,7 +37,7 @@ require (
 	github.com/tidwall/sjson v1.2.5 // indirect
 	github.com/yuin/goldmark v1.5.4 // indirect
 	go.mau.fi/libsignal v0.1.0 // indirect
-	go.mau.fi/zeroconfig v0.1.0 // indirect
+	go.mau.fi/zeroconfig v0.1.1 // indirect
 	golang.org/x/crypto v0.6.0 // indirect
 	golang.org/x/sys v0.5.0 // indirect
 	golang.org/x/text v0.7.0 // indirect

+ 4 - 4
go.sum

@@ -69,8 +69,8 @@ go.mau.fi/libsignal v0.1.0 h1:vAKI/nJ5tMhdzke4cTK1fb0idJzz1JuEIpmjprueC+c=
 go.mau.fi/libsignal v0.1.0/go.mod h1:R8ovrTezxtUNzCQE5PH30StOQWWeBskBsWE55vMfY9I=
 go.mau.fi/whatsmeow v0.0.0-20230306190159-5caded34a872 h1:jrIWy0l9kTxl7bdp3muFofZcyLyI1xxE7BXWeldVKr0=
 go.mau.fi/whatsmeow v0.0.0-20230306190159-5caded34a872/go.mod h1:zoTtv1CupGEyTew7TOwnBmTbHB4pVad2OzjTf5CVwa0=
-go.mau.fi/zeroconfig v0.1.0 h1:SDGgreQevNJHb+QqGAs2Ff+OPXcGdO8rZencqP4BJi4=
-go.mau.fi/zeroconfig v0.1.0/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70=
+go.mau.fi/zeroconfig v0.1.1 h1:igLhBbCkaO8yxtxCfzy28k3yitzXU43LcOwpWmpBjz4=
+go.mau.fi/zeroconfig v0.1.1/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
@@ -127,5 +127,5 @@ maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
 maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
 maunium.net/go/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8=
 maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho=
-maunium.net/go/mautrix v0.15.0-beta.2 h1:J7sEehF7taahVtoCsM6E41VauaBNQMPCCcxYCe/0Zbk=
-maunium.net/go/mautrix v0.15.0-beta.2/go.mod h1:AE3TCX9q4W7fYfrL/1RsuOell9rTUBO27XUULuwArH4=
+maunium.net/go/mautrix v0.15.0-beta.2.0.20230308151314-83fcdcf30f00 h1:tlEAjIGSnxZd2MDvgAIw946KoxqWQq/SJDEchoCJM0M=
+maunium.net/go/mautrix v0.15.0-beta.2.0.20230308151314-83fcdcf30f00/go.mod h1:Ay2u2JljEKX2rEfA2Ss8Wxkj1tkAhUClpA+exZc7imk=

+ 37 - 3
portal.go

@@ -120,6 +120,16 @@ func (br *WABridge) GetPortalByJID(key database.PortalKey) *Portal {
 	return portal
 }
 
+func (br *WABridge) GetExistingPortalByJID(key database.PortalKey) *Portal {
+	br.portalsLock.Lock()
+	defer br.portalsLock.Unlock()
+	portal, ok := br.portalsByJID[key]
+	if !ok {
+		return br.loadDBPortal(br.DB.Portal.GetByJID(key), nil)
+	}
+	return portal
+}
+
 func (br *WABridge) GetAllPortals() []*Portal {
 	return br.dbPortalsToPortals(br.DB.Portal.GetAll())
 }
@@ -1866,15 +1876,35 @@ func (portal *Portal) SetReply(content *event.MessageEventContent, replyTo *Repl
 	if replyTo == nil {
 		return false
 	}
-	message := portal.bridge.DB.Message.GetByJID(portal.Key, replyTo.MessageID)
+	key := portal.Key
+	targetPortal := portal
+	defer func() {
+		if content.RelatesTo != nil && content.RelatesTo.InReplyTo != nil && targetPortal != portal {
+			content.RelatesTo.InReplyTo.UnstableRoomID = targetPortal.MXID
+		}
+	}()
+	if portal.bridge.Config.Bridge.CrossRoomReplies && !replyTo.Chat.IsEmpty() && replyTo.Chat != key.JID {
+		if replyTo.Chat.Server == types.GroupServer {
+			key = database.NewPortalKey(replyTo.Chat, types.EmptyJID)
+		} else if replyTo.Chat == types.BroadcastServerJID {
+			key = database.NewPortalKey(replyTo.Chat, key.Receiver)
+		}
+		if key != portal.Key {
+			targetPortal = portal.bridge.GetExistingPortalByJID(key)
+			if targetPortal == nil {
+				return false
+			}
+		}
+	}
+	message := portal.bridge.DB.Message.GetByJID(key, replyTo.MessageID)
 	if message == nil || message.IsFakeMXID() {
 		if isBackfill && portal.bridge.Config.Homeserver.Software == bridgeconfig.SoftwareHungry {
-			content.RelatesTo = (&event.RelatesTo{}).SetReplyTo(portal.deterministicEventID(replyTo.Sender, replyTo.MessageID, ""))
+			content.RelatesTo = (&event.RelatesTo{}).SetReplyTo(targetPortal.deterministicEventID(replyTo.Sender, replyTo.MessageID, ""))
 			return true
 		}
 		return false
 	}
-	evt, err := portal.MainIntent().GetEvent(portal.MXID, message.MXID)
+	evt, err := targetPortal.MainIntent().GetEvent(targetPortal.MXID, message.MXID)
 	if err != nil {
 		portal.log.Warnln("Failed to get reply target:", err)
 		content.RelatesTo = (&event.RelatesTo{}).SetReplyTo(message.MXID)
@@ -2017,12 +2047,14 @@ func (portal *Portal) sendMessage(intent *appservice.IntentAPI, eventType event.
 
 type ReplyInfo struct {
 	MessageID types.MessageID
+	Chat      types.JID
 	Sender    types.JID
 }
 
 type Replyable interface {
 	GetStanzaId() string
 	GetParticipant() string
+	GetRemoteJid() string
 }
 
 func GetReply(replyable Replyable) *ReplyInfo {
@@ -2033,8 +2065,10 @@ func GetReply(replyable Replyable) *ReplyInfo {
 	if err != nil {
 		return nil
 	}
+	chat, _ := types.ParseJID(replyable.GetRemoteJid())
 	return &ReplyInfo{
 		MessageID: types.MessageID(replyable.GetStanzaId()),
+		Chat:      chat,
 		Sender:    sender,
 	}
 }