mirror of
https://github.com/tulir/mautrix-whatsapp
synced 2024-12-13 17:13:11 +01:00
Add WhatsApp->Matrix read receipts and phone connection notifications
This commit is contained in:
parent
60529bf022
commit
1f87deb317
12 changed files with 178 additions and 69 deletions
|
@ -28,7 +28,7 @@
|
||||||
* [x] Avatars
|
* [x] Avatars
|
||||||
* [ ] Presence
|
* [ ] Presence
|
||||||
* [ ] Typing notifications
|
* [ ] Typing notifications
|
||||||
* [ ] Read receipts
|
* [x] Read receipts
|
||||||
* [ ] Admin/superadmin status
|
* [ ] Admin/superadmin status
|
||||||
* [ ] Membership actions
|
* [ ] Membership actions
|
||||||
* [ ] Invite
|
* [ ] Invite
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (mq *MessageQuery) GetAll(owner types.MatrixUserID) (messages []*Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mq *MessageQuery) GetByJID(owner types.MatrixUserID, jid types.WhatsAppMessageID) *Message {
|
func (mq *MessageQuery) GetByJID(owner types.MatrixUserID, jid types.WhatsAppMessageID) *Message {
|
||||||
return mq.get("SELECT * FROM message WHERE jid=?", jid)
|
return mq.get("SELECT * FROM message WHERE owner=? AND jid=?", owner, jid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mq *MessageQuery) GetByMXID(mxid types.MatrixEventID) *Message {
|
func (mq *MessageQuery) GetByMXID(mxid types.MatrixEventID) *Message {
|
||||||
|
|
|
@ -93,7 +93,7 @@ func (puppet *Puppet) Insert() error {
|
||||||
_, err := puppet.db.Exec("INSERT INTO puppet VALUES (?, ?, ?, ?)",
|
_, err := puppet.db.Exec("INSERT INTO puppet VALUES (?, ?, ?, ?)",
|
||||||
puppet.JID, puppet.Receiver, puppet.Displayname, puppet.Avatar)
|
puppet.JID, puppet.Receiver, puppet.Displayname, puppet.Avatar)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
puppet.log.Errorln("Failed to insert %s->%s: %v", puppet.JID, puppet.Receiver, err)
|
puppet.log.Errorfln("Failed to insert %s->%s: %v", puppet.JID, puppet.Receiver, err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ func (puppet *Puppet) Update() error {
|
||||||
puppet.Displayname, puppet.Avatar,
|
puppet.Displayname, puppet.Avatar,
|
||||||
puppet.JID, puppet.Receiver)
|
puppet.JID, puppet.Receiver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
puppet.log.Errorln("Failed to update %s->%s: %v", puppet.JID, puppet.Receiver, err)
|
puppet.log.Errorfln("Failed to update %s->%s: %v", puppet.JID, puppet.Receiver, err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
81
portal.go
81
portal.go
|
@ -17,21 +17,24 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"maunium.net/go/mautrix-whatsapp/database"
|
|
||||||
log "maunium.net/go/maulogger"
|
|
||||||
"fmt"
|
|
||||||
"maunium.net/go/mautrix-whatsapp/types"
|
|
||||||
"maunium.net/go/gomatrix"
|
|
||||||
"strings"
|
|
||||||
"maunium.net/go/mautrix-appservice"
|
|
||||||
"github.com/Rhymen/go-whatsapp"
|
|
||||||
"sync"
|
|
||||||
"net/http"
|
|
||||||
"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
|
|
||||||
"mime"
|
|
||||||
"image"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"math/rand"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/Rhymen/go-whatsapp"
|
||||||
|
"maunium.net/go/gomatrix"
|
||||||
"maunium.net/go/gomatrix/format"
|
"maunium.net/go/gomatrix/format"
|
||||||
|
log "maunium.net/go/maulogger"
|
||||||
|
"maunium.net/go/mautrix-appservice"
|
||||||
|
"maunium.net/go/mautrix-whatsapp/database"
|
||||||
|
"maunium.net/go/mautrix-whatsapp/types"
|
||||||
|
"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (user *User) GetPortalByMXID(mxid types.MatrixRoomID) *Portal {
|
func (user *User) GetPortalByMXID(mxid types.MatrixRoomID) *Portal {
|
||||||
|
@ -221,7 +224,7 @@ func (portal *Portal) CreateMatrixRoom() error {
|
||||||
name := portal.Name
|
name := portal.Name
|
||||||
topic := portal.Topic
|
topic := portal.Topic
|
||||||
isPrivateChat := false
|
isPrivateChat := false
|
||||||
if strings.HasSuffix(portal.JID, "s.whatsapp.net") {
|
if strings.HasSuffix(portal.JID, whatsapp_ext.NewUserSuffix) {
|
||||||
puppet := portal.user.GetPuppetByJID(portal.JID)
|
puppet := portal.user.GetPuppetByJID(portal.JID)
|
||||||
name = puppet.Displayname
|
name = puppet.Displayname
|
||||||
topic = "WhatsApp private chat"
|
topic = "WhatsApp private chat"
|
||||||
|
@ -244,7 +247,7 @@ func (portal *Portal) CreateMatrixRoom() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) IsPrivateChat() bool {
|
func (portal *Portal) IsPrivateChat() bool {
|
||||||
return strings.HasSuffix(portal.JID, puppetJIDStrippedSuffix)
|
return strings.HasSuffix(portal.JID, whatsapp_ext.NewUserSuffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) MainIntent() *appservice.IntentAPI {
|
func (portal *Portal) MainIntent() *appservice.IntentAPI {
|
||||||
|
@ -282,13 +285,18 @@ func (portal *Portal) GetMessageIntent(info whatsapp.MessageInfo) *appservice.In
|
||||||
return puppet.Intent()
|
return puppet.Intent()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (portal *Portal) GetRelations(info whatsapp.MessageInfo) (reply gomatrix.RelatesTo) {
|
func (portal *Portal) SetReply(content *gomatrix.Content, info whatsapp.MessageInfo) {
|
||||||
if len(info.QuotedMessageID) == 0 {
|
if len(info.QuotedMessageID) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
message := portal.bridge.DB.Message.GetByJID(portal.Owner, info.QuotedMessageID)
|
message := portal.bridge.DB.Message.GetByJID(portal.Owner, info.QuotedMessageID)
|
||||||
if message != nil {
|
if message != nil {
|
||||||
reply.InReplyTo.EventID = message.MXID
|
event, err := portal.MainIntent().GetEvent(portal.MXID, message.MXID)
|
||||||
|
if err != nil {
|
||||||
|
portal.log.Warnln("Failed to get reply target:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
content.SetReply(event)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -299,18 +307,24 @@ func (portal *Portal) HandleTextMessage(message whatsapp.TextMessage) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
portal.CreateMatrixRoom()
|
err := portal.CreateMatrixRoom()
|
||||||
|
if err != nil {
|
||||||
|
portal.log.Errorln("Failed to create portal room:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
intent := portal.GetMessageIntent(message.Info)
|
intent := portal.GetMessageIntent(message.Info)
|
||||||
if intent == nil {
|
if intent == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := intent.SendMassagedMessageEvent(portal.MXID, gomatrix.EventMessage, gomatrix.Content{
|
content := gomatrix.Content{
|
||||||
Body: message.Text,
|
Body: message.Text,
|
||||||
MsgType: gomatrix.MsgText,
|
MsgType: gomatrix.MsgText,
|
||||||
RelatesTo: portal.GetRelations(message.Info),
|
}
|
||||||
}, int64(message.Info.Timestamp*1000))
|
portal.SetReply(&content, message.Info)
|
||||||
|
|
||||||
|
resp, err := intent.SendMassagedMessageEvent(portal.MXID, gomatrix.EventMessage, content, int64(message.Info.Timestamp*1000))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
portal.log.Errorfln("Failed to handle message %s: %v", message.Info.Id, err)
|
portal.log.Errorfln("Failed to handle message %s: %v", message.Info.Id, err)
|
||||||
return
|
return
|
||||||
|
@ -324,7 +338,11 @@ func (portal *Portal) HandleMediaMessage(download func() ([]byte, error), thumbn
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
portal.CreateMatrixRoom()
|
err := portal.CreateMatrixRoom()
|
||||||
|
if err != nil {
|
||||||
|
portal.log.Errorln("Failed to create portal room:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
intent := portal.GetMessageIntent(info)
|
intent := portal.GetMessageIntent(info)
|
||||||
if intent == nil {
|
if intent == nil {
|
||||||
|
@ -353,12 +371,12 @@ func (portal *Portal) HandleMediaMessage(download func() ([]byte, error), thumbn
|
||||||
content := gomatrix.Content{
|
content := gomatrix.Content{
|
||||||
Body: caption,
|
Body: caption,
|
||||||
URL: uploaded.ContentURI,
|
URL: uploaded.ContentURI,
|
||||||
Info: gomatrix.FileInfo{
|
Info: &gomatrix.FileInfo{
|
||||||
Size: len(data),
|
Size: len(data),
|
||||||
MimeType: mimeType,
|
MimeType: mimeType,
|
||||||
},
|
},
|
||||||
RelatesTo: portal.GetRelations(info),
|
|
||||||
}
|
}
|
||||||
|
portal.SetReply(&content, info)
|
||||||
|
|
||||||
if thumbnail != nil {
|
if thumbnail != nil {
|
||||||
thumbnailMime := http.DetectContentType(thumbnail)
|
thumbnailMime := http.DetectContentType(thumbnail)
|
||||||
|
@ -422,6 +440,12 @@ var htmlParser = format.HTMLParser{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeMessageID() string {
|
||||||
|
b := make([]byte, 10)
|
||||||
|
rand.Read(b)
|
||||||
|
return strings.ToUpper(hex.EncodeToString(b))
|
||||||
|
}
|
||||||
|
|
||||||
func (portal *Portal) HandleMatrixMessage(evt *gomatrix.Event) {
|
func (portal *Portal) HandleMatrixMessage(evt *gomatrix.Event) {
|
||||||
var err error
|
var err error
|
||||||
switch evt.Content.MsgType {
|
switch evt.Content.MsgType {
|
||||||
|
@ -430,18 +454,21 @@ func (portal *Portal) HandleMatrixMessage(evt *gomatrix.Event) {
|
||||||
if evt.Content.Format == gomatrix.FormatHTML {
|
if evt.Content.Format == gomatrix.FormatHTML {
|
||||||
text = htmlParser.Parse(evt.Content.FormattedBody)
|
text = htmlParser.Parse(evt.Content.FormattedBody)
|
||||||
}
|
}
|
||||||
|
id := makeMessageID()
|
||||||
err = portal.user.Conn.Send(whatsapp.TextMessage{
|
err = portal.user.Conn.Send(whatsapp.TextMessage{
|
||||||
Text: text,
|
Text: text,
|
||||||
Info: whatsapp.MessageInfo{
|
Info: whatsapp.MessageInfo{
|
||||||
|
Id: id,
|
||||||
RemoteJid: portal.JID,
|
RemoteJid: portal.JID,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
portal.MarkHandled(id, evt.ID)
|
||||||
default:
|
default:
|
||||||
portal.log.Debugln("Unhandled Matrix event:", evt)
|
portal.log.Debugln("Unhandled Matrix event:", evt)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
portal.log.Errorln("Error handling Matrix event %s: %v", evt.ID, err)
|
portal.log.Errorfln("Error handling Matrix event %s: %v", evt.ID, err)
|
||||||
} else {
|
} else {
|
||||||
portal.log.Debugln("Handled Matrix event:", evt)
|
portal.log.Debugln("Handled Matrix event:", evt)
|
||||||
}
|
}
|
||||||
|
|
22
puppet.go
22
puppet.go
|
@ -17,18 +17,18 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"maunium.net/go/mautrix-whatsapp/database"
|
|
||||||
log "maunium.net/go/maulogger"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"maunium.net/go/mautrix-whatsapp/types"
|
|
||||||
"strings"
|
|
||||||
"maunium.net/go/mautrix-appservice"
|
|
||||||
"github.com/Rhymen/go-whatsapp"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
const puppetJIDStrippedSuffix = "@s.whatsapp.net"
|
"github.com/Rhymen/go-whatsapp"
|
||||||
|
log "maunium.net/go/maulogger"
|
||||||
|
"maunium.net/go/mautrix-appservice"
|
||||||
|
"maunium.net/go/mautrix-whatsapp/database"
|
||||||
|
"maunium.net/go/mautrix-whatsapp/types"
|
||||||
|
"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
|
||||||
|
)
|
||||||
|
|
||||||
func (bridge *Bridge) ParsePuppetMXID(mxid types.MatrixUserID) (types.MatrixUserID, types.WhatsAppID, bool) {
|
func (bridge *Bridge) ParsePuppetMXID(mxid types.MatrixUserID) (types.MatrixUserID, types.WhatsAppID, bool) {
|
||||||
userIDRegex, err := regexp.Compile(fmt.Sprintf("^@%s:%s$",
|
userIDRegex, err := regexp.Compile(fmt.Sprintf("^@%s:%s$",
|
||||||
|
@ -47,7 +47,7 @@ func (bridge *Bridge) ParsePuppetMXID(mxid types.MatrixUserID) (types.MatrixUser
|
||||||
receiver = strings.Replace(receiver, "=40", "@", 1)
|
receiver = strings.Replace(receiver, "=40", "@", 1)
|
||||||
colonIndex := strings.LastIndex(receiver, "=3")
|
colonIndex := strings.LastIndex(receiver, "=3")
|
||||||
receiver = receiver[:colonIndex] + ":" + receiver[colonIndex+len("=3"):]
|
receiver = receiver[:colonIndex] + ":" + receiver[colonIndex+len("=3"):]
|
||||||
jid := types.WhatsAppID(match[2] + puppetJIDStrippedSuffix)
|
jid := types.WhatsAppID(match[2] + whatsapp_ext.NewUserSuffix)
|
||||||
return receiver, jid, true
|
return receiver, jid, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ func (user *User) NewPuppet(dbPuppet *database.Puppet) *Puppet {
|
||||||
dbPuppet.Receiver,
|
dbPuppet.Receiver,
|
||||||
strings.Replace(
|
strings.Replace(
|
||||||
dbPuppet.JID,
|
dbPuppet.JID,
|
||||||
puppetJIDStrippedSuffix, "", 1)),
|
whatsapp_ext.NewUserSuffix, "", 1)),
|
||||||
user.bridge.Config.Homeserver.Domain),
|
user.bridge.Config.Homeserver.Domain),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
66
user.go
66
user.go
|
@ -17,14 +17,16 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"maunium.net/go/mautrix-whatsapp/database"
|
"fmt"
|
||||||
"github.com/Rhymen/go-whatsapp"
|
|
||||||
"time"
|
|
||||||
"github.com/skip2/go-qrcode"
|
|
||||||
log "maunium.net/go/maulogger"
|
|
||||||
"maunium.net/go/mautrix-whatsapp/types"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Rhymen/go-whatsapp"
|
||||||
|
"github.com/skip2/go-qrcode"
|
||||||
|
log "maunium.net/go/maulogger"
|
||||||
|
"maunium.net/go/mautrix-whatsapp/database"
|
||||||
|
"maunium.net/go/mautrix-whatsapp/types"
|
||||||
"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
|
"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -186,7 +188,7 @@ func (user *User) Sync() {
|
||||||
user.log.Debugln("Syncing...")
|
user.log.Debugln("Syncing...")
|
||||||
user.Conn.Contacts()
|
user.Conn.Contacts()
|
||||||
for jid, contact := range user.Conn.Store.Contacts {
|
for jid, contact := range user.Conn.Store.Contacts {
|
||||||
if strings.HasSuffix(jid, puppetJIDStrippedSuffix) {
|
if strings.HasSuffix(jid, whatsapp_ext.NewUserSuffix) {
|
||||||
puppet := user.GetPuppetByJID(contact.Jid)
|
puppet := user.GetPuppetByJID(contact.Jid)
|
||||||
puppet.Sync(contact)
|
puppet.Sync(contact)
|
||||||
}
|
}
|
||||||
|
@ -205,6 +207,10 @@ func (user *User) HandleError(err error) {
|
||||||
user.log.Errorln("WhatsApp error:", err)
|
user.log.Errorln("WhatsApp error:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (user *User) HandleJSONParseError(err error) {
|
||||||
|
user.log.Errorln("WhatsApp JSON parse error:", err)
|
||||||
|
}
|
||||||
|
|
||||||
func (user *User) HandleTextMessage(message whatsapp.TextMessage) {
|
func (user *User) HandleTextMessage(message whatsapp.TextMessage) {
|
||||||
user.log.Debugln("Received text message:", message)
|
user.log.Debugln("Received text message:", message)
|
||||||
portal := user.GetPortalByJID(message.Info.RemoteJid)
|
portal := user.GetPortalByJID(message.Info.RemoteJid)
|
||||||
|
@ -231,6 +237,52 @@ func (user *User) HandleDocumentMessage(message whatsapp.DocumentMessage) {
|
||||||
portal.HandleMediaMessage(message.Download, message.Thumbnail, message.Info, message.Type, message.Title)
|
portal.HandleMediaMessage(message.Download, message.Thumbnail, message.Info, message.Type, message.Title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (user *User) HandleStreamEvent(stream whatsapp_ext.StreamEvent) {
|
||||||
|
if len(user.ManagementRoom) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch stream.Type {
|
||||||
|
case whatsapp_ext.StreamSleep:
|
||||||
|
user.bridge.AppService.BotIntent().SendNotice(user.ManagementRoom, "WhatsApp client disconnected.")
|
||||||
|
case whatsapp_ext.StreamUpdate:
|
||||||
|
if user.Conn.Info != nil && user.Conn.Info.Phone != nil {
|
||||||
|
user.bridge.AppService.BotIntent().SendNotice(user.ManagementRoom,
|
||||||
|
fmt.Sprintf("WhatsApp v%s client connected from %s %s (OS v%s).",
|
||||||
|
user.Conn.Info.Phone.WaVersion, user.Conn.Info.Phone.DeviceManufacturer, user.Conn.Info.Phone.DeviceModel, user.Conn.Info.Phone.OsVersion))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *User) HandleConnInfo(info whatsapp_ext.ConnInfo) {
|
||||||
|
if len(user.ManagementRoom) > 0 && len(info.ProtocolVersion) > 0 {
|
||||||
|
user.bridge.AppService.BotIntent().SendNotice(user.ManagementRoom,
|
||||||
|
fmt.Sprintf("WhatsApp v%s client connected from %s %s (OS v%s).",
|
||||||
|
info.Phone.WhatsAppVersion, info.Phone.DeviceManufacturer, info.Phone.DeviceModel, info.Phone.OSVersion))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *User) HandleMsgInfo(info whatsapp_ext.MsgInfo) {
|
||||||
|
if (info.Command == whatsapp_ext.MsgInfoCommandAck || info.Command == whatsapp_ext.MsgInfoCommandAcks) && info.Acknowledgement == whatsapp_ext.AckMessageRead {
|
||||||
|
portal := user.GetPortalByJID(info.ToJID)
|
||||||
|
if len(portal.MXID) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
intent := user.GetPuppetByJID(info.SenderJID).Intent()
|
||||||
|
user.log.Debugln(info.IDs)
|
||||||
|
for _, id := range info.IDs {
|
||||||
|
msg := user.bridge.DB.Message.GetByJID(user.ID, id)
|
||||||
|
if msg == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err := intent.MarkRead(portal.MXID, msg.MXID)
|
||||||
|
if err != nil {
|
||||||
|
user.log.Warnln("Failed to mark message %s as read by %s: %v", msg.MXID, info.SenderJID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (user *User) HandleJsonMessage(message string) {
|
func (user *User) HandleJsonMessage(message string) {
|
||||||
user.log.Debugln("JSON message:", message)
|
user.log.Debugln("JSON message:", message)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,9 @@
|
||||||
package whatsapp_ext
|
package whatsapp_ext
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/Rhymen/go-whatsapp"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/Rhymen/go-whatsapp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConnInfo struct {
|
type ConnInfo struct {
|
||||||
|
@ -26,8 +27,8 @@ type ConnInfo struct {
|
||||||
BinaryVersion int `json:"binVersion"`
|
BinaryVersion int `json:"binVersion"`
|
||||||
Phone struct {
|
Phone struct {
|
||||||
WhatsAppVersion string `json:"wa_version"`
|
WhatsAppVersion string `json:"wa_version"`
|
||||||
MCC int `json:"mcc"`
|
MCC string `json:"mcc"`
|
||||||
MNC int `json:"mnc"`
|
MNC string `json:"mnc"`
|
||||||
OSVersion string `json:"os_version"`
|
OSVersion string `json:"os_version"`
|
||||||
DeviceManufacturer string `json:"device_manufacturer"`
|
DeviceManufacturer string `json:"device_manufacturer"`
|
||||||
DeviceModel string `json:"device_model"`
|
DeviceModel string `json:"device_model"`
|
||||||
|
|
|
@ -18,6 +18,7 @@ package whatsapp_ext
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/Rhymen/go-whatsapp"
|
"github.com/Rhymen/go-whatsapp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ type JSONMessageType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MessageMsgInfo JSONMessageType = "MsgInfo"
|
MessageMsgInfo JSONMessageType = "MsgInfo"
|
||||||
|
MessageMsg JSONMessageType = "Msg"
|
||||||
MessagePresence JSONMessageType = "Presence"
|
MessagePresence JSONMessageType = "Presence"
|
||||||
MessageStream JSONMessageType = "Stream"
|
MessageStream JSONMessageType = "Stream"
|
||||||
MessageConn JSONMessageType = "Conn"
|
MessageConn JSONMessageType = "Conn"
|
||||||
|
@ -76,11 +78,11 @@ func (ext *ExtendedConn) HandleJsonMessage(message string) {
|
||||||
case MessageStream:
|
case MessageStream:
|
||||||
ext.handleMessageStream(msg[1:])
|
ext.handleMessageStream(msg[1:])
|
||||||
case MessageConn:
|
case MessageConn:
|
||||||
ext.handleMessageProps(msg[1])
|
ext.handleMessageConn(msg[1])
|
||||||
case MessageProps:
|
case MessageProps:
|
||||||
ext.handleMessageProps(msg[1])
|
ext.handleMessageProps(msg[1])
|
||||||
case MessageMsgInfo:
|
case MessageMsgInfo, MessageMsg:
|
||||||
ext.handleMessageMsgInfo(msg[1])
|
ext.handleMessageMsgInfo(msgType, msg[1])
|
||||||
default:
|
default:
|
||||||
for _, handler := range ext.handlers {
|
for _, handler := range ext.handlers {
|
||||||
ujmHandler, ok := handler.(UnhandledJSONMessageHandler)
|
ujmHandler, ok := handler.(UnhandledJSONMessageHandler)
|
||||||
|
|
|
@ -17,25 +17,49 @@
|
||||||
package whatsapp_ext
|
package whatsapp_ext
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/Rhymen/go-whatsapp"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Rhymen/go-whatsapp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MsgInfoCommand string
|
type MsgInfoCommand string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MsgInfoCommandAcknowledge MsgInfoCommand = "ack"
|
MsgInfoCommandAck MsgInfoCommand = "ack"
|
||||||
|
MsgInfoCommandAcks MsgInfoCommand = "acks"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Acknowledgement int
|
||||||
|
|
||||||
|
const (
|
||||||
|
AckMessageSent Acknowledgement = 1
|
||||||
|
AckMessageDelivered Acknowledgement = 2
|
||||||
|
AckMessageRead Acknowledgement = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
type JSONStringOrArray []string
|
||||||
|
|
||||||
|
func (jsoa *JSONStringOrArray) UnmarshalJSON(data []byte) error {
|
||||||
|
var str string
|
||||||
|
if json.Unmarshal(data, &str) == nil {
|
||||||
|
*jsoa = []string{str}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var strs []string
|
||||||
|
json.Unmarshal(data, &strs)
|
||||||
|
*jsoa = strs
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type MsgInfo struct {
|
type MsgInfo struct {
|
||||||
Command MsgInfoCommand `json:"cmd"`
|
Command MsgInfoCommand `json:"cmd"`
|
||||||
ID string `json:"id"`
|
IDs JSONStringOrArray `json:"id"`
|
||||||
Acknowledgement int `json:"ack"`
|
Acknowledgement Acknowledgement `json:"ack"`
|
||||||
MessageFromJID string `json:"from"`
|
MessageFromJID string `json:"from"`
|
||||||
SenderJID string `json:"participant"`
|
SenderJID string `json:"participant"`
|
||||||
ToJID string `json:"to"`
|
ToJID string `json:"to"`
|
||||||
Timestamp int64 `json:"t"`
|
Timestamp int64 `json:"t"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MsgInfoHandler interface {
|
type MsgInfoHandler interface {
|
||||||
|
@ -43,7 +67,7 @@ type MsgInfoHandler interface {
|
||||||
HandleMsgInfo(MsgInfo)
|
HandleMsgInfo(MsgInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ext *ExtendedConn) handleMessageMsgInfo(message []byte) {
|
func (ext *ExtendedConn) handleMessageMsgInfo(msgType JSONMessageType, message []byte) {
|
||||||
var event MsgInfo
|
var event MsgInfo
|
||||||
err := json.Unmarshal(message, &event)
|
err := json.Unmarshal(message, &event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -53,11 +77,14 @@ func (ext *ExtendedConn) handleMessageMsgInfo(message []byte) {
|
||||||
event.MessageFromJID = strings.Replace(event.MessageFromJID, OldUserSuffix, NewUserSuffix, 1)
|
event.MessageFromJID = strings.Replace(event.MessageFromJID, OldUserSuffix, NewUserSuffix, 1)
|
||||||
event.SenderJID = strings.Replace(event.SenderJID, OldUserSuffix, NewUserSuffix, 1)
|
event.SenderJID = strings.Replace(event.SenderJID, OldUserSuffix, NewUserSuffix, 1)
|
||||||
event.ToJID = strings.Replace(event.ToJID, OldUserSuffix, NewUserSuffix, 1)
|
event.ToJID = strings.Replace(event.ToJID, OldUserSuffix, NewUserSuffix, 1)
|
||||||
|
if msgType == MessageMsg {
|
||||||
|
event.SenderJID = event.MessageFromJID
|
||||||
|
}
|
||||||
for _, handler := range ext.handlers {
|
for _, handler := range ext.handlers {
|
||||||
msgInfoHandler, ok := handler.(MsgInfoHandler)
|
msgInfoHandler, ok := handler.(MsgInfoHandler)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
msgInfoHandler.HandleMsgInfo(event)
|
go msgInfoHandler.HandleMsgInfo(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,6 @@ func (ext *ExtendedConn) handleMessagePresence(message []byte) {
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
presenceHandler.HandlePresence(event)
|
go presenceHandler.HandlePresence(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,6 @@ func (ext *ExtendedConn) handleMessageProps(message []byte) {
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
protocolPropsHandler.HandleProtocolProps(event)
|
go protocolPropsHandler.HandleProtocolProps(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,6 @@ func (ext *ExtendedConn) handleMessageStream(message []json.RawMessage) {
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
streamHandler.HandleStreamEvent(event)
|
go streamHandler.HandleStreamEvent(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue