From 629bce50ad8122b09b9a7cf3b3c18e20809065fd Mon Sep 17 00:00:00 2001 From: Yousef Mansy Date: Sat, 18 Feb 2023 01:15:37 -0800 Subject: [PATCH] Handle Whatsapp threading/replies. In this change we are updating whatsapp message IDs to include sender JID as this is necessary to reply to a message https://github.com/tulir/whatsmeow/issues/88#issuecomment-1093195237 https://github.com/tulir/whatsmeow/discussions/148#discussioncomment-3094325 Based on commit 6afa93e537c53b371db37f35a3546ff0fb669416 from #1934 Author: Iiro Laiho --- bridge/whatsappmulti/handlers.go | 26 +++++++++++++++++------- bridge/whatsappmulti/helpers.go | 15 ++++++++++++++ bridge/whatsappmulti/whatsapp.go | 35 ++++++++++++++++++++++++++++++-- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/bridge/whatsappmulti/handlers.go b/bridge/whatsappmulti/handlers.go index 34dce471af..cd0dc8ffae 100644 --- a/bridge/whatsappmulti/handlers.go +++ b/bridge/whatsappmulti/handlers.go @@ -1,3 +1,4 @@ +//go:build whatsappmulti // +build whatsappmulti package bwhatsapp @@ -93,8 +94,12 @@ func (b *Bwhatsapp) handleTextMessage(messageInfo types.MessageInfo, msg *proto. Account: b.Account, Protocol: b.Protocol, Extra: make(map[string][]interface{}), - // ParentID: TODO, // TODO handle thread replies // map from Info.QuotedMessageID string - ID: messageInfo.ID, + ID: getMessageIdFormat(senderJID.String(), messageInfo.ID), + } + + if msg.GetExtendedTextMessage() != nil { + ci := msg.GetExtendedTextMessage().GetContextInfo() + appendParentID(ci, &rmsg) } if avatarURL, exists := b.userAvatars[senderJID.String()]; exists { @@ -126,9 +131,11 @@ func (b *Bwhatsapp) handleImageMessage(msg *events.Message) { Account: b.Account, Protocol: b.Protocol, Extra: make(map[string][]interface{}), - ID: msg.Info.ID, + ID: getMessageIdFormat(senderJID.String(), msg.Info.ID), } + appendParentID(ci, &rmsg) + if avatarURL, exists := b.userAvatars[senderJID.String()]; exists { rmsg.Avatar = avatarURL } @@ -189,9 +196,11 @@ func (b *Bwhatsapp) handleVideoMessage(msg *events.Message) { Account: b.Account, Protocol: b.Protocol, Extra: make(map[string][]interface{}), - ID: msg.Info.ID, + ID: getMessageIdFormat(senderJID.String(), msg.Info.ID), } + appendParentID(ci, &rmsg) + if avatarURL, exists := b.userAvatars[senderJID.String()]; exists { rmsg.Avatar = avatarURL } @@ -238,7 +247,6 @@ func (b *Bwhatsapp) handleAudioMessage(msg *events.Message) { if senderJID == (types.JID{}) && ci.Participant != nil { senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer) } - rmsg := config.Message{ UserID: senderJID.String(), Username: senderName, @@ -246,9 +254,11 @@ func (b *Bwhatsapp) handleAudioMessage(msg *events.Message) { Account: b.Account, Protocol: b.Protocol, Extra: make(map[string][]interface{}), - ID: msg.Info.ID, + ID: getMessageIdFormat(senderJID.String(), msg.Info.ID), } + appendParentID(ci, &rmsg) + if avatarURL, exists := b.userAvatars[senderJID.String()]; exists { rmsg.Avatar = avatarURL } @@ -303,9 +313,11 @@ func (b *Bwhatsapp) handleDocumentMessage(msg *events.Message) { Account: b.Account, Protocol: b.Protocol, Extra: make(map[string][]interface{}), - ID: msg.Info.ID, + ID: getMessageIdFormat(senderJID.String(), msg.Info.ID), } + appendParentID(ci, &rmsg) + if avatarURL, exists := b.userAvatars[senderJID.String()]; exists { rmsg.Avatar = avatarURL } diff --git a/bridge/whatsappmulti/helpers.go b/bridge/whatsappmulti/helpers.go index 75d9f5fdd1..513286f0ae 100644 --- a/bridge/whatsappmulti/helpers.go +++ b/bridge/whatsappmulti/helpers.go @@ -7,7 +7,10 @@ import ( "fmt" "strings" + "github.com/42wim/matterbridge/bridge/config" + "go.mau.fi/whatsmeow" + "go.mau.fi/whatsmeow/binary/proto" "go.mau.fi/whatsmeow/store" "go.mau.fi/whatsmeow/store/sqlstore" "go.mau.fi/whatsmeow/types" @@ -122,3 +125,15 @@ func (b *Bwhatsapp) getDevice() (*store.Device, error) { return device, nil } + +func appendParentID(ci *proto.ContextInfo, rmsg *config.Message) { + + if ci != nil && ci.StanzaId != nil { + // rmsg.ParentID = *ci.StanzaId + rmsg.ParentID = getMessageIdFormat(*ci.Participant, *ci.StanzaId) + } +} + +func getMessageIdFormat(authorJID string, messageID string) string { + return fmt.Sprintf("%s:%s", authorJID, messageID) +} diff --git a/bridge/whatsappmulti/whatsapp.go b/bridge/whatsappmulti/whatsapp.go index 76e4ae4680..40a526fc00 100644 --- a/bridge/whatsappmulti/whatsapp.go +++ b/bridge/whatsappmulti/whatsapp.go @@ -10,6 +10,7 @@ import ( "mime" "os" "path/filepath" + "strings" "time" "github.com/42wim/matterbridge/bridge" @@ -402,12 +403,42 @@ func (b *Bwhatsapp) Send(msg config.Message) (string, error) { text := msg.Username + msg.Text + ID := whatsmeow.GenerateMessageID() + + // If we have a parent ID send an extended message + if msg.ParentID != "" { + // in appendParentID() we combine the "Participant" and the "StanzaID" as both are needed to send a reply + replyInfo := strings.Split(msg.ParentID, ":") + + if len(replyInfo) != 2 { + b.Log.Debug("Malformed reply info to whatsapp: %s", msg.ParentID) + } else { + // Send message with reply (not working) + // https://github.com/tulir/whatsmeow/issues/88#issuecomment-1093195237 + _, err := b.wc.SendMessage( + context.Background(), + groupJID, + &proto.Message{ + ExtendedTextMessage: &proto.ExtendedTextMessage{ + Text: &text, + ContextInfo: &proto.ContextInfo{ + StanzaId: &replyInfo[1], + Participant: &replyInfo[0], + }, + }, + }, + whatsmeow.SendRequestExtra{ID: ID}, + ) + + return getMessageIdFormat(b.Config.GetString("Number")[1:]+"@s.whatsapp.net", ID), err + } + } + var message proto.Message message.Conversation = &text - ID := whatsmeow.GenerateMessageID() _, err := b.wc.SendMessage(context.TODO(), groupJID, &message, whatsmeow.SendRequestExtra{ID: ID}) - return ID, err + return getMessageIdFormat(b.Config.GetString("Number")[1:]+"@s.whatsapp.net", ID), err }