diff --git a/go.mod b/go.mod index 36e18a3..2da183a 100644 --- a/go.mod +++ b/go.mod @@ -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-20211109215855-2e8804d7e690 + go.mau.fi/whatsmeow v0.0.0-20211110182414-ba28bae40fb5 golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d google.golang.org/protobuf v1.27.1 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b diff --git a/go.sum b/go.sum index 3083abf..ea2698a 100644 --- a/go.sum +++ b/go.sum @@ -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-20211109153248-a67163214910 h1:9FFhG0OmkuMau5UEaTgiUQ+7cSbtbOQ7hiWKdN8OI3I= go.mau.fi/libsignal v0.0.0-20211109153248-a67163214910/go.mod h1:AufGrvVh+00Nc07Jm4hTquh7yleZyn20tKJI2wCPAKg= -go.mau.fi/whatsmeow v0.0.0-20211109215855-2e8804d7e690 h1:Yx5v2ut+kd5YG+bLhCxqPnCEZ+yau2wKsQerk3VYtbY= -go.mau.fi/whatsmeow v0.0.0-20211109215855-2e8804d7e690/go.mod h1:8jUjOAi3xtGubxcZgG8uSHpAdyQXBRbWAfxkctX/4y4= +go.mau.fi/whatsmeow v0.0.0-20211110182414-ba28bae40fb5 h1:ERlXDWd0vj62SldgFSqCkjtVpyUgmxRtyKMH20ADW7Q= +go.mau.fi/whatsmeow v0.0.0-20211110182414-ba28bae40fb5/go.mod h1:8jUjOAi3xtGubxcZgG8uSHpAdyQXBRbWAfxkctX/4y4= 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= diff --git a/user.go b/user.go index f687e96..c7b2321 100644 --- a/user.go +++ b/user.go @@ -722,58 +722,32 @@ func (user *User) handleReceipt(receipt *events.Receipt) { if portal == nil || len(portal.MXID) == 0 { return } - if receipt.IsFromMe { - user.markSelfRead(portal, receipt.MessageID) - } else { - intent := user.bridge.GetPuppetByJID(receipt.Sender).IntentFor(portal) - ok := user.markOtherRead(portal, intent, receipt.MessageID) - if !ok { - // Message not found, try any previous IDs - for i := len(receipt.PreviousIDs) - 1; i >= 0; i-- { - ok = user.markOtherRead(portal, intent, receipt.PreviousIDs[i]) - if ok { - break - } - } + // The order of the message ID array depends on the sender's platform, so we just have to find + // the last message based on timestamp. Also, timestamps only have second precision, so if + // there are many messages at the same second just mark them all as read, because we don't + // know which one is last + markAsRead := make([]*database.Message, 0, 1) + var bestTimestamp time.Time + for _, msgID := range receipt.MessageIDs { + msg := user.bridge.DB.Message.GetByJID(portal.Key, msgID) + if msg == nil || msg.IsFakeMXID() { + continue + } + if msg.Timestamp.After(bestTimestamp) { + bestTimestamp = msg.Timestamp + markAsRead = append(markAsRead[:0], msg) + } else if msg != nil && msg.Timestamp.Equal(bestTimestamp) { + markAsRead = append(markAsRead, msg) } } -} - -func (user *User) markOtherRead(portal *Portal, intent *appservice.IntentAPI, messageID types.MessageID) bool { - msg := user.bridge.DB.Message.GetByJID(portal.Key, messageID) - if msg == nil || msg.IsFakeMXID() { - return false - } - - err := intent.MarkReadWithContent(portal.MXID, msg.MXID, &CustomReadReceipt{DoublePuppet: intent.IsCustomPuppet}) - if err != nil { - user.log.Warnfln("Failed to mark message %s as read by %s: %v", msg.MXID, intent.UserID, err) - } - return true -} - -func (user *User) markSelfRead(portal *Portal, messageID types.MessageID) { - puppet := user.bridge.GetPuppetByCustomMXID(user.MXID) - if puppet == nil || puppet.CustomIntent() == nil { - return - } - var message *database.Message - if messageID == "" { - message = user.bridge.DB.Message.GetLastInChat(portal.Key) - if message == nil { - return + intent := user.bridge.GetPuppetByJID(receipt.Sender).IntentFor(portal) + for _, msg := range markAsRead { + err := intent.MarkReadWithContent(portal.MXID, msg.MXID, &CustomReadReceipt{DoublePuppet: intent.IsCustomPuppet}) + if err != nil { + user.log.Warnfln("Failed to mark message %s as read by %s: %v", msg.MXID, intent.UserID, err) + } else { + user.log.Debugfln("Marked %s as read by %s", msg.MXID, intent.UserID) } - user.log.Debugfln("User read chat %s/%s in WhatsApp mobile (last known event: %s/%s)", portal.Key.JID, portal.MXID, message.JID, message.MXID) - } else { - message = user.bridge.DB.Message.GetByJID(portal.Key, messageID) - if message == nil || message.IsFakeMXID() { - return - } - user.log.Debugfln("User read message %s/%s in %s/%s in WhatsApp mobile", message.JID, message.MXID, portal.Key.JID, portal.MXID) - } - err := puppet.CustomIntent().MarkReadWithContent(portal.MXID, message.MXID, &CustomReadReceipt{DoublePuppet: true}) - if err != nil { - user.log.Warnfln("Failed to bridge own read receipt in %s: %v", portal.Key.JID, err) } } @@ -788,7 +762,7 @@ func (user *User) markSelfReadFull(portal *Portal) { } err := puppet.CustomIntent().MarkReadWithContent(portal.MXID, lastMessage.MXID, &CustomReadReceipt{DoublePuppet: true}) if err != nil { - user.log.Warnfln("Failed to mark %s in %s as read after backfill: %v", lastMessage.MXID, portal.MXID, err) + user.log.Warnfln("Failed to mark %s (last message) in %s as read: %v", lastMessage.MXID, portal.MXID, err) } }