Re-add call start notices

This commit is contained in:
Tulir Asokan 2021-11-02 15:46:31 +02:00
parent 817cd21550
commit e0d79f2de1
7 changed files with 78 additions and 16 deletions

View file

@ -34,11 +34,7 @@ type BridgeConfig struct {
DeliveryReceipts bool `yaml:"delivery_receipts"`
PortalMessageBuffer int `yaml:"portal_message_buffer"`
CallNotices struct {
Start bool `yaml:"start"`
End bool `yaml:"end"`
} `yaml:"call_notices"`
CallStartNotices bool `yaml:"call_start_notices"`
HistorySync struct {
CreatePortals bool `yaml:"create_portals"`

View file

@ -124,6 +124,10 @@ func (msg *Message) IsFakeMXID() bool {
return strings.HasPrefix(msg.MXID.String(), "net.maunium.whatsapp.fake::")
}
func (msg *Message) IsFakeJID() bool {
return strings.HasPrefix(msg.JID, "FAKE::")
}
func (msg *Message) Scan(row Scannable) *Message {
var ts int64
err := row.Scan(&msg.Chat.JID, &msg.Chat.Receiver, &msg.JID, &msg.MXID, &msg.Sender, &ts, &msg.Sent, &msg.DecryptionError)

View file

@ -85,11 +85,8 @@ bridge:
# Should the bridge send a read receipt from the bridge bot when a message has been sent to WhatsApp?
delivery_receipts: false
# Should notices of incoming calls be sent to Matrix?
call_notices:
start: true
end: true
# Should incoming calls send a message to the Matrix room?
call_start_notices: true
# Settings for handling history sync payloads. These settings only apply right after login,
# because the phone only sends the history sync data once, and there's no way to re-request it

2
go.mod
View file

@ -8,7 +8,7 @@ require (
github.com/mattn/go-sqlite3 v1.14.9
github.com/prometheus/client_golang v1.11.0
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
go.mau.fi/whatsmeow v0.0.0-20211101191317-2837c184bbfe
go.mau.fi/whatsmeow v0.0.0-20211102134251-7e0b153d9c9e
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
google.golang.org/protobuf v1.27.1
gopkg.in/yaml.v2 v2.4.0

4
go.sum
View file

@ -139,8 +139,8 @@ github.com/tidwall/sjson v1.2.3 h1:5+deguEhHSEjmuICXZ21uSSsXotWMA0orU783+Z7Cp8=
github.com/tidwall/sjson v1.2.3/go.mod h1:5WdjKx3AQMvCJ4RG6/2UYT7dLrGvJUV1x4jdTAyGvZs=
go.mau.fi/libsignal v0.0.0-20211024113310-f9fc6a1855f2 h1:xpQTMgJGGaF+c8jV/LA/FVXAPJxZbSAGeflOc+Ly6uQ=
go.mau.fi/libsignal v0.0.0-20211024113310-f9fc6a1855f2/go.mod h1:3XlVlwOfp8f9Wri+C1D4ORqgUsN4ZvunJOoPjQMBhos=
go.mau.fi/whatsmeow v0.0.0-20211101191317-2837c184bbfe h1:ohSAIsW4Jg5GD2r0b+827vgQmheMKCMyhb7AGFppBDg=
go.mau.fi/whatsmeow v0.0.0-20211101191317-2837c184bbfe/go.mod h1:ODEmmqeUn9eBDQHFc1S902YA3YFLtmaBujYRRFl53jI=
go.mau.fi/whatsmeow v0.0.0-20211102134251-7e0b153d9c9e h1:HVlRWzEEmWkgInvj8VGxB3epRSd7ryRvLdAA2X0fbGk=
go.mau.fi/whatsmeow v0.0.0-20211102134251-7e0b153d9c9e/go.mod h1:ODEmmqeUn9eBDQHFc1S902YA3YFLtmaBujYRRFl53jI=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=

View file

@ -161,9 +161,17 @@ func (bridge *Bridge) NewPortal(dbPortal *database.Portal) *Portal {
const recentlyHandledLength = 100
type fakeMessage struct {
Sender types.JID
Text string
ID string
Time time.Time
}
type PortalMessage struct {
evt *events.Message
undecryptable *events.UndecryptableMessage
fake *fakeMessage
source *User
}
@ -196,7 +204,7 @@ type Portal struct {
func (portal *Portal) handleMessageLoop() {
for msg := range portal.messages {
if len(portal.MXID) == 0 {
if msg.evt == nil || !containsSupportedMessage(msg.evt.Message) {
if msg.fake == nil && (msg.evt == nil || !containsSupportedMessage(msg.evt.Message)) {
portal.log.Debugln("Not creating portal room for incoming message: message is not a chat message")
continue
}
@ -211,6 +219,9 @@ func (portal *Portal) handleMessageLoop() {
portal.handleMessage(msg.source, msg.evt)
} else if msg.undecryptable != nil {
portal.handleUndecryptableMessage(msg.source, msg.undecryptable)
} else if msg.fake != nil {
msg.fake.ID = "FAKE::" + msg.fake.ID
portal.handleFakeMessage(*msg.fake)
} else {
portal.log.Warnln("Unexpected PortalMessage with no message: %+v", msg)
}
@ -336,6 +347,32 @@ func (portal *Portal) handleUndecryptableMessage(source *User, evt *events.Undec
portal.finishHandling(nil, &evt.Info, resp.EventID, true)
}
func (portal *Portal) handleFakeMessage(msg fakeMessage) {
if portal.isRecentlyHandled(msg.ID, false) {
portal.log.Debugfln("Not handling %s (fake): message was recently handled", msg.ID)
return
} else if existingMsg := portal.bridge.DB.Message.GetByJID(portal.Key, msg.ID); existingMsg != nil {
portal.log.Debugfln("Not handling %s (fake): message is duplicate", msg.ID)
return
}
intent := portal.bridge.GetPuppetByJID(msg.Sender).IntentFor(portal)
resp, err := portal.sendMessage(intent, event.EventMessage, &event.MessageEventContent{
MsgType: event.MsgText,
Body: msg.Text,
}, nil, msg.Time.UnixMilli())
if err != nil {
portal.log.Errorln("Failed to send %s to Matrix: %v", msg.ID, err)
} else {
portal.finishHandling(nil, &types.MessageInfo{
ID: msg.ID,
Timestamp: msg.Time,
MessageSource: types.MessageSource{
Sender: msg.Sender,
},
}, resp.EventID, false)
}
}
func (portal *Portal) handleMessage(source *User, evt *events.Message) {
if len(portal.MXID) == 0 {
portal.log.Warnln("handleMessage called even though portal.MXID is empty")
@ -2140,7 +2177,7 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP
replyToID := content.GetReplyTo()
if len(replyToID) > 0 {
replyToMsg := portal.bridge.DB.Message.GetByMXID(replyToID)
if replyToMsg != nil {
if replyToMsg != nil && !replyToMsg.IsFakeJID() {
ctxInfo.StanzaId = &replyToMsg.JID
ctxInfo.Participant = proto.String(replyToMsg.Sender.ToNonAD().String())
// Using blank content here seems to work fine on all official WhatsApp apps.
@ -2360,6 +2397,9 @@ func (portal *Portal) HandleMatrixRedaction(sender *User, evt *event.Event) {
if msg == nil {
portal.log.Debugfln("Ignoring redaction %s of unknown event by %s", msg, senderLogIdentifier)
return
} else if msg.IsFakeJID() {
portal.log.Debugfln("Ignoring redaction %s of fake event by %s", msg, senderLogIdentifier)
return
} else if msg.Sender.User != sender.JID.User {
portal.log.Debugfln("Ignoring redaction %s of %s/%s by %s: message was sent by someone else (%s, not %s)", evt.ID, msg.MXID, msg.JID, senderLogIdentifier, msg.Sender, sender.JID)
return

27
user.go
View file

@ -358,7 +358,7 @@ func containsSupportedMessages(conv *waProto.Conversation) bool {
type portalToBackfill struct {
portal *Portal
conv *waProto.Conversation
conv *waProto.Conversation
}
func (user *User) handleHistorySync(evt *waProto.HistorySync) {
@ -423,6 +423,25 @@ func (user *User) handleHistorySync(evt *waProto.HistorySync) {
user.log.Infofln("Finished handling history sync with type %s, chunk order %d, progress %d%%", evt.GetSyncType(), evt.GetChunkOrder(), evt.GetProgress())
}
func (user *User) handleCallStart(sender types.JID, id, callType string) {
if !user.bridge.Config.Bridge.CallStartNotices {
return
}
portal := user.GetPortalByJID(sender)
text := "Incoming call"
if callType != "" {
text = fmt.Sprintf("Incoming %s call", text)
}
portal.messages <- PortalMessage{
fake: &fakeMessage{
Sender: sender,
Text: text,
ID: id,
},
source: user,
}
}
func (user *User) HandleEvent(event interface{}) {
switch v := event.(type) {
case *events.LoggedOut:
@ -482,6 +501,12 @@ func (user *User) HandleEvent(event interface{}) {
case *events.Message:
portal := user.GetPortalByJID(v.Info.Chat)
portal.messages <- PortalMessage{evt: v, source: user}
case *events.CallOffer:
user.handleCallStart(v.CallCreator, v.CallID, "")
case *events.CallOfferNotice:
user.handleCallStart(v.CallCreator, v.CallID, v.Type)
case *events.CallTerminate, *events.CallRelayLatency, *events.CallAccept, *events.UnknownCallEvent:
// ignore
case *events.UndecryptableMessage:
portal := user.GetPortalByJID(v.Info.Chat)
portal.messages <- PortalMessage{undecryptable: v, source: user}