summaryrefslogtreecommitdiffstats
path: root/bridge
diff options
context:
space:
mode:
Diffstat (limited to 'bridge')
-rw-r--r--bridge/whatsappmulti/handlers.go24
-rw-r--r--bridge/whatsappmulti/helpers.go63
-rw-r--r--bridge/whatsappmulti/whatsapp.go72
3 files changed, 135 insertions, 24 deletions
diff --git a/bridge/whatsappmulti/handlers.go b/bridge/whatsappmulti/handlers.go
index fd75be09..b8e78572 100644
--- a/bridge/whatsappmulti/handlers.go
+++ b/bridge/whatsappmulti/handlers.go
@@ -1,3 +1,4 @@
+//go:build whatsappmulti
// +build whatsappmulti
package bwhatsapp
@@ -89,6 +90,12 @@ func (b *Bwhatsapp) handleTextMessage(messageInfo types.MessageInfo, msg *proto.
}
}
+ parentID := ""
+ if msg.GetExtendedTextMessage() != nil {
+ ci := msg.GetExtendedTextMessage().GetContextInfo()
+ parentID = getParentIdFromCtx(ci)
+ }
+
rmsg := config.Message{
UserID: senderJID.String(),
Username: senderName,
@@ -97,8 +104,8 @@ 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, messageInfo.ID),
+ ParentID: parentID,
}
if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
@@ -130,7 +137,8 @@ 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, msg.Info.ID),
+ ParentID: getParentIdFromCtx(ci),
}
if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
@@ -193,7 +201,8 @@ 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, msg.Info.ID),
+ ParentID: getParentIdFromCtx(ci),
}
if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
@@ -251,7 +260,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,
@@ -259,7 +267,8 @@ 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, msg.Info.ID),
+ ParentID: getParentIdFromCtx(ci),
}
if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
@@ -316,7 +325,8 @@ 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, msg.Info.ID),
+ ParentID: getParentIdFromCtx(ci),
}
if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
diff --git a/bridge/whatsappmulti/helpers.go b/bridge/whatsappmulti/helpers.go
index 75d9f5fd..963eafa1 100644
--- a/bridge/whatsappmulti/helpers.go
+++ b/bridge/whatsappmulti/helpers.go
@@ -7,7 +7,10 @@ import (
"fmt"
"strings"
+ goproto "google.golang.org/protobuf/proto"
+
"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,63 @@ func (b *Bwhatsapp) getDevice() (*store.Device, error) {
return device, nil
}
+
+func (b *Bwhatsapp) getNewReplyContext(parentID string) (*proto.ContextInfo, error) {
+ replyInfo, err := b.parseMessageID(parentID)
+
+ if err != nil {
+ return nil, err
+ }
+
+ sender := fmt.Sprintf("%s@%s", replyInfo.Sender.User, replyInfo.Sender.Server)
+ ctx := &proto.ContextInfo{
+ StanzaId: &replyInfo.MessageID,
+ Participant: &sender,
+ QuotedMessage: &proto.Message{Conversation: goproto.String("")},
+ }
+
+ return ctx, nil
+}
+
+func (b *Bwhatsapp) parseMessageID(id string) (*Replyable, error) {
+ // No message ID in case action is executed on a message sent before the bridge was started
+ // and then the bridge cache doesn't have this message ID mapped
+ if id == "" {
+ return &Replyable{MessageID: id}, nil
+ }
+
+ replyInfo := strings.Split(id, "/")
+
+ if len(replyInfo) == 2 {
+ sender, err := types.ParseJID(replyInfo[0])
+
+ if err == nil {
+ return &Replyable{
+ MessageID: types.MessageID(replyInfo[1]),
+ Sender: sender,
+ }, nil
+ }
+ }
+
+ err := fmt.Errorf("MessageID does not match format of {senderJID}:{messageID} : \"%s\"", id)
+
+ return &Replyable{MessageID: id}, err
+}
+
+func getParentIdFromCtx(ci *proto.ContextInfo) string {
+ if ci != nil && ci.StanzaId != nil {
+ senderJid, err := types.ParseJID(*ci.Participant)
+
+ if err == nil {
+ return getMessageIdFormat(senderJid, *ci.StanzaId)
+ }
+ }
+
+ return ""
+}
+
+func getMessageIdFormat(jid types.JID, messageID string) string {
+ // we're crafting our own JID str as AD JID format messes with how stuff looks on a webclient
+ jidStr := fmt.Sprintf("%s@%s", jid.User, jid.Server)
+ return fmt.Sprintf("%s/%s", jidStr, messageID)
+}
diff --git a/bridge/whatsappmulti/whatsapp.go b/bridge/whatsappmulti/whatsapp.go
index 76e4ae46..6798d827 100644
--- a/bridge/whatsappmulti/whatsapp.go
+++ b/bridge/whatsappmulti/whatsapp.go
@@ -42,6 +42,11 @@ type Bwhatsapp struct {
userAvatars map[string]string
}
+type Replyable struct {
+ MessageID types.MessageID
+ Sender types.JID
+}
+
// New Create a new WhatsApp bridge. This will be called for each [whatsapp.<server>] entry you have in the config file
func New(cfg *bridge.Config) bridge.Bridger {
number := cfg.GetString(cfgNumber)
@@ -222,6 +227,10 @@ func (b *Bwhatsapp) PostDocumentMessage(msg config.Message, filetype string) (st
// Post document message
var message proto.Message
+ var ctx *proto.ContextInfo
+ if msg.ParentID != "" {
+ ctx, _ = b.getNewReplyContext(msg.ParentID)
+ }
message.DocumentMessage = &proto.DocumentMessage{
Title: &fi.Name,
@@ -233,6 +242,7 @@ func (b *Bwhatsapp) PostDocumentMessage(msg config.Message, filetype string) (st
FileSha256: resp.FileSHA256,
FileLength: goproto.Uint64(resp.FileLength),
Url: &resp.URL,
+ ContextInfo: ctx,
}
b.Log.Debugf("=> Sending %#v as a document", msg)
@@ -246,8 +256,6 @@ func (b *Bwhatsapp) PostDocumentMessage(msg config.Message, filetype string) (st
// Post an image message from the bridge to WhatsApp
// Handle, for sure image/jpeg, image/png and image/gif MIME types
func (b *Bwhatsapp) PostImageMessage(msg config.Message, filetype string) (string, error) {
- groupJID, _ := types.ParseJID(msg.Channel)
-
fi := msg.Extra["file"][0].(config.FileInfo)
caption := msg.Username + fi.Comment
@@ -258,6 +266,10 @@ func (b *Bwhatsapp) PostImageMessage(msg config.Message, filetype string) (strin
}
var message proto.Message
+ var ctx *proto.ContextInfo
+ if msg.ParentID != "" {
+ ctx, _ = b.getNewReplyContext(msg.ParentID)
+ }
message.ImageMessage = &proto.ImageMessage{
Mimetype: &filetype,
@@ -267,20 +279,16 @@ func (b *Bwhatsapp) PostImageMessage(msg config.Message, filetype string) (strin
FileSha256: resp.FileSHA256,
FileLength: goproto.Uint64(resp.FileLength),
Url: &resp.URL,
+ ContextInfo: ctx,
}
b.Log.Debugf("=> Sending %#v as an image", msg)
- ID := whatsmeow.GenerateMessageID()
- _, err = b.wc.SendMessage(context.TODO(), groupJID, &message, whatsmeow.SendRequestExtra{ID: ID})
-
- return ID, err
+ return b.sendMessage(msg, &message)
}
// Post a video message from the bridge to WhatsApp
func (b *Bwhatsapp) PostVideoMessage(msg config.Message, filetype string) (string, error) {
- groupJID, _ := types.ParseJID(msg.Channel)
-
fi := msg.Extra["file"][0].(config.FileInfo)
caption := msg.Username + fi.Comment
@@ -291,6 +299,10 @@ func (b *Bwhatsapp) PostVideoMessage(msg config.Message, filetype string) (strin
}
var message proto.Message
+ var ctx *proto.ContextInfo
+ if msg.ParentID != "" {
+ ctx, _ = b.getNewReplyContext(msg.ParentID)
+ }
message.VideoMessage = &proto.VideoMessage{
Mimetype: &filetype,
@@ -300,14 +312,12 @@ func (b *Bwhatsapp) PostVideoMessage(msg config.Message, filetype string) (strin
FileSha256: resp.FileSHA256,
FileLength: goproto.Uint64(resp.FileLength),
Url: &resp.URL,
+ ContextInfo: ctx,
}
b.Log.Debugf("=> Sending %#v as a video", msg)
- ID := whatsmeow.GenerateMessageID()
- _, err = b.wc.SendMessage(context.TODO(), groupJID, &message, whatsmeow.SendRequestExtra{ID: ID})
-
- return ID, err
+ return b.sendMessage(msg, &message)
}
// Post audio inline
@@ -322,6 +332,10 @@ func (b *Bwhatsapp) PostAudioMessage(msg config.Message, filetype string) (strin
}
var message proto.Message
+ var ctx *proto.ContextInfo
+ if msg.ParentID != "" {
+ ctx, _ = b.getNewReplyContext(msg.ParentID)
+ }
message.AudioMessage = &proto.AudioMessage{
Mimetype: &filetype,
@@ -330,12 +344,12 @@ func (b *Bwhatsapp) PostAudioMessage(msg config.Message, filetype string) (strin
FileSha256: resp.FileSHA256,
FileLength: goproto.Uint64(resp.FileLength),
Url: &resp.URL,
+ ContextInfo: ctx,
}
b.Log.Debugf("=> Sending %#v as audio", msg)
- ID := whatsmeow.GenerateMessageID()
- _, err = b.wc.SendMessage(context.TODO(), groupJID, &message, whatsmeow.SendRequestExtra{ID: ID})
+ ID, err := b.sendMessage(msg, &message)
var captionMessage proto.Message
caption := msg.Username + fi.Comment + "\u2B06" // the char on the end is upwards arrow emoji
@@ -351,6 +365,9 @@ func (b *Bwhatsapp) PostAudioMessage(msg config.Message, filetype string) (strin
func (b *Bwhatsapp) Send(msg config.Message) (string, error) {
groupJID, _ := types.ParseJID(msg.Channel)
+ extendedMsgID, _ := b.parseMessageID(msg.ID)
+ msg.ID = extendedMsgID.MessageID
+
b.Log.Debugf("=> Receiving %#v", msg)
// Delete message
@@ -400,14 +417,35 @@ func (b *Bwhatsapp) Send(msg config.Message) (string, error) {
}
}
+ var message proto.Message
text := msg.Username + msg.Text
- var message proto.Message
+ // If we have a parent ID send an extended message
+ if msg.ParentID != "" {
+ replyContext, err := b.getNewReplyContext(msg.ParentID)
+
+ if err == nil {
+ message = proto.Message{
+ ExtendedTextMessage: &proto.ExtendedTextMessage{
+ Text: &text,
+ ContextInfo: replyContext,
+ },
+ }
+
+ return b.sendMessage(msg, &message)
+ }
+ }
message.Conversation = &text
+ return b.sendMessage(msg, &message)
+}
+
+func (b *Bwhatsapp) sendMessage(rmsg config.Message, message *proto.Message) (string, error) {
+ groupJID, _ := types.ParseJID(rmsg.Channel)
ID := whatsmeow.GenerateMessageID()
- _, err := b.wc.SendMessage(context.TODO(), groupJID, &message, whatsmeow.SendRequestExtra{ID: ID})
- return ID, err
+ _, err := b.wc.SendMessage(context.Background(), groupJID, message, whatsmeow.SendRequestExtra{ID: ID})
+
+ return getMessageIdFormat(*b.wc.Store.ID, ID), err
}