summaryrefslogtreecommitdiffstats
path: root/bridge/whatsappmulti/handlers.go
diff options
context:
space:
mode:
authorWim <wim@42.be>2022-03-20 02:20:54 +0100
committerWim <wim@42.be>2022-03-20 14:57:48 +0100
commit496d5b4ec7f5f4afae6199f928675d14d18de015 (patch)
tree3a649c80a76f0ffc33e6b3a63c0e65e892169cde /bridge/whatsappmulti/handlers.go
parent2623a412c42a81104b97ae8c81a5f66760fee4b6 (diff)
downloadmatterbridge-msglm-496d5b4ec7f5f4afae6199f928675d14d18de015.tar.gz
matterbridge-msglm-496d5b4ec7f5f4afae6199f928675d14d18de015.tar.bz2
matterbridge-msglm-496d5b4ec7f5f4afae6199f928675d14d18de015.zip
Add whatsappmulti buildflag for whatsapp with multidevice support (whatsapp)
Diffstat (limited to 'bridge/whatsappmulti/handlers.go')
-rw-r--r--bridge/whatsappmulti/handlers.go344
1 files changed, 344 insertions, 0 deletions
diff --git a/bridge/whatsappmulti/handlers.go b/bridge/whatsappmulti/handlers.go
new file mode 100644
index 00000000..c6b96a5e
--- /dev/null
+++ b/bridge/whatsappmulti/handlers.go
@@ -0,0 +1,344 @@
+// +build whatsappmulti
+
+package bwhatsapp
+
+import (
+ "fmt"
+ "mime"
+ "strings"
+
+ "github.com/42wim/matterbridge/bridge/config"
+ "github.com/42wim/matterbridge/bridge/helper"
+
+ "go.mau.fi/whatsmeow/binary/proto"
+ "go.mau.fi/whatsmeow/types"
+ "go.mau.fi/whatsmeow/types/events"
+)
+
+// nolint:gocritic
+func (b *Bwhatsapp) eventHandler(evt interface{}) {
+ switch e := evt.(type) {
+ case *events.Message:
+ b.handleMessage(e)
+ }
+}
+
+func (b *Bwhatsapp) handleMessage(message *events.Message) {
+ msg := message.Message
+ switch {
+ case msg == nil, message.Info.IsFromMe, message.Info.Timestamp.Before(b.startedAt):
+ return
+ }
+
+ b.Log.Infof("Receiving message %#v", msg)
+
+ switch {
+ case msg.Conversation != nil || msg.ExtendedTextMessage != nil:
+ b.handleTextMessage(message.Info, msg)
+ case msg.VideoMessage != nil:
+ b.handleVideoMessage(message)
+ case msg.AudioMessage != nil:
+ b.handleAudioMessage(message)
+ case msg.DocumentMessage != nil:
+ b.handleDocumentMessage(message)
+ case msg.ImageMessage != nil:
+ b.handleImageMessage(message)
+ }
+}
+
+// nolint:funlen
+func (b *Bwhatsapp) handleTextMessage(messageInfo types.MessageInfo, msg *proto.Message) {
+ senderJID := messageInfo.Sender
+ channel := messageInfo.Chat
+
+ senderName := b.getSenderName(messageInfo.Sender)
+ if senderName == "" {
+ senderName = "Someone" // don't expose telephone number
+ }
+
+ if msg.GetExtendedTextMessage() == nil && msg.GetConversation() == "" {
+ b.Log.Debugf("message without text content? %#v", msg)
+ return
+ }
+
+ var text string
+
+ // nolint:nestif
+ if msg.GetExtendedTextMessage() == nil {
+ text = msg.GetConversation()
+ } else {
+ text = msg.GetExtendedTextMessage().GetText()
+ ci := msg.GetExtendedTextMessage().GetContextInfo()
+
+ if senderJID == (types.JID{}) && ci.Participant != nil {
+ senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
+ }
+
+ if ci.MentionedJid != nil {
+ // handle user mentions
+ for _, mentionedJID := range ci.MentionedJid {
+ numberAndSuffix := strings.SplitN(mentionedJID, "@", 2)
+
+ // mentions comes as telephone numbers and we don't want to expose it to other bridges
+ // replace it with something more meaninful to others
+ mention := b.getSenderNotify(types.NewJID(numberAndSuffix[0], types.DefaultUserServer))
+ if mention == "" {
+ mention = "someone"
+ }
+
+ text = strings.Replace(text, "@"+numberAndSuffix[0], "@"+mention, 1)
+ }
+ }
+ }
+
+ rmsg := config.Message{
+ UserID: senderJID.String(),
+ Username: senderName,
+ Text: text,
+ Channel: channel.String(),
+ 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,
+ }
+
+ if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
+ rmsg.Avatar = avatarURL
+ }
+
+ b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
+ b.Log.Debugf("<= Message is %#v", rmsg)
+
+ b.Remote <- rmsg
+}
+
+// HandleImageMessage sent from WhatsApp, relay it to the brige
+func (b *Bwhatsapp) handleImageMessage(msg *events.Message) {
+ imsg := msg.Message.GetImageMessage()
+
+ senderJID := msg.Info.Sender
+ senderName := b.getSenderName(senderJID)
+ ci := imsg.GetContextInfo()
+
+ if senderJID == (types.JID{}) && ci.Participant != nil {
+ senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
+ }
+
+ rmsg := config.Message{
+ UserID: senderJID.String(),
+ Username: senderName,
+ Channel: msg.Info.Chat.String(),
+ Account: b.Account,
+ Protocol: b.Protocol,
+ Extra: make(map[string][]interface{}),
+ ID: msg.Info.ID,
+ }
+
+ if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
+ rmsg.Avatar = avatarURL
+ }
+
+ fileExt, err := mime.ExtensionsByType(imsg.GetMimetype())
+ if err != nil {
+ b.Log.Errorf("Mimetype detection error: %s", err)
+
+ return
+ }
+
+ // rename .jfif to .jpg https://github.com/42wim/matterbridge/issues/1292
+ if fileExt[0] == ".jfif" {
+ fileExt[0] = ".jpg"
+ }
+
+ // rename .jpe to .jpg https://github.com/42wim/matterbridge/issues/1463
+ if fileExt[0] == ".jpe" {
+ fileExt[0] = ".jpg"
+ }
+
+ filename := fmt.Sprintf("%v%v", msg.Info.ID, fileExt[0])
+
+ b.Log.Debugf("Trying to download %s with type %s", filename, imsg.GetMimetype())
+
+ data, err := b.wc.Download(imsg)
+ if err != nil {
+ b.Log.Errorf("Download image failed: %s", err)
+
+ return
+ }
+
+ // Move file to bridge storage
+ helper.HandleDownloadData(b.Log, &rmsg, filename, imsg.GetCaption(), "", &data, b.General)
+
+ b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
+ b.Log.Debugf("<= Message is %#v", rmsg)
+
+ b.Remote <- rmsg
+}
+
+// HandleVideoMessage downloads video messages
+func (b *Bwhatsapp) handleVideoMessage(msg *events.Message) {
+ imsg := msg.Message.GetVideoMessage()
+
+ senderJID := msg.Info.Sender
+ senderName := b.getSenderName(senderJID)
+ ci := imsg.GetContextInfo()
+
+ if senderJID == (types.JID{}) && ci.Participant != nil {
+ senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
+ }
+
+ rmsg := config.Message{
+ UserID: senderJID.String(),
+ Username: senderName,
+ Channel: msg.Info.Chat.String(),
+ Account: b.Account,
+ Protocol: b.Protocol,
+ Extra: make(map[string][]interface{}),
+ ID: msg.Info.ID,
+ }
+
+ if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
+ rmsg.Avatar = avatarURL
+ }
+
+ fileExt, err := mime.ExtensionsByType(imsg.GetMimetype())
+ if err != nil {
+ b.Log.Errorf("Mimetype detection error: %s", err)
+
+ return
+ }
+
+ if len(fileExt) == 0 {
+ fileExt = append(fileExt, ".mp4")
+ }
+
+ filename := fmt.Sprintf("%v%v", msg.Info.ID, fileExt[0])
+
+ b.Log.Debugf("Trying to download %s with size %#v and type %s", filename, imsg.GetFileLength(), imsg.GetMimetype())
+
+ data, err := b.wc.Download(imsg)
+ if err != nil {
+ b.Log.Errorf("Download video failed: %s", err)
+
+ return
+ }
+
+ // Move file to bridge storage
+ helper.HandleDownloadData(b.Log, &rmsg, filename, imsg.GetCaption(), "", &data, b.General)
+
+ b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
+ b.Log.Debugf("<= Message is %#v", rmsg)
+
+ b.Remote <- rmsg
+}
+
+// HandleAudioMessage downloads audio messages
+func (b *Bwhatsapp) handleAudioMessage(msg *events.Message) {
+ imsg := msg.Message.GetAudioMessage()
+
+ senderJID := msg.Info.Sender
+ senderName := b.getSenderName(senderJID)
+ ci := imsg.GetContextInfo()
+
+ if senderJID == (types.JID{}) && ci.Participant != nil {
+ senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
+ }
+
+ rmsg := config.Message{
+ UserID: senderJID.String(),
+ Username: senderName,
+ Channel: msg.Info.Chat.String(),
+ Account: b.Account,
+ Protocol: b.Protocol,
+ Extra: make(map[string][]interface{}),
+ ID: msg.Info.ID,
+ }
+
+ if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
+ rmsg.Avatar = avatarURL
+ }
+
+ fileExt, err := mime.ExtensionsByType(imsg.GetMimetype())
+ if err != nil {
+ b.Log.Errorf("Mimetype detection error: %s", err)
+
+ return
+ }
+
+ if len(fileExt) == 0 {
+ fileExt = append(fileExt, ".ogg")
+ }
+
+ filename := fmt.Sprintf("%v%v", msg.Info.ID, fileExt[0])
+
+ b.Log.Debugf("Trying to download %s with size %#v and type %s", filename, imsg.GetFileLength(), imsg.GetMimetype())
+
+ data, err := b.wc.Download(imsg)
+ if err != nil {
+ b.Log.Errorf("Download video failed: %s", err)
+
+ return
+ }
+
+ // Move file to bridge storage
+ helper.HandleDownloadData(b.Log, &rmsg, filename, "audio message", "", &data, b.General)
+
+ b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
+ b.Log.Debugf("<= Message is %#v", rmsg)
+
+ b.Remote <- rmsg
+}
+
+// HandleDocumentMessage downloads documents
+func (b *Bwhatsapp) handleDocumentMessage(msg *events.Message) {
+ imsg := msg.Message.GetDocumentMessage()
+
+ senderJID := msg.Info.Sender
+ senderName := b.getSenderName(senderJID)
+ ci := imsg.GetContextInfo()
+
+ if senderJID == (types.JID{}) && ci.Participant != nil {
+ senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
+ }
+
+ rmsg := config.Message{
+ UserID: senderJID.String(),
+ Username: senderName,
+ Channel: msg.Info.Chat.String(),
+ Account: b.Account,
+ Protocol: b.Protocol,
+ Extra: make(map[string][]interface{}),
+ ID: msg.Info.ID,
+ }
+
+ if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
+ rmsg.Avatar = avatarURL
+ }
+
+ fileExt, err := mime.ExtensionsByType(imsg.GetMimetype())
+ if err != nil {
+ b.Log.Errorf("Mimetype detection error: %s", err)
+
+ return
+ }
+
+ filename := fmt.Sprintf("%v", imsg.GetFileName())
+
+ b.Log.Debugf("Trying to download %s with extension %s and type %s", filename, fileExt, imsg.GetMimetype())
+
+ data, err := b.wc.Download(imsg)
+ if err != nil {
+ b.Log.Errorf("Download document message failed: %s", err)
+
+ return
+ }
+
+ // Move file to bridge storage
+ helper.HandleDownloadData(b.Log, &rmsg, filename, "document", "", &data, b.General)
+
+ b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
+ b.Log.Debugf("<= Message is %#v", rmsg)
+
+ b.Remote <- rmsg
+}