This commit is contained in:
Karmanyaah Malhotra 2021-02-21 22:46:17 -05:00
parent 7cb9983da8
commit f1c093896e
9 changed files with 311 additions and 279 deletions

View File

@ -22,8 +22,7 @@ import (
"strings"
"text/template"
"github.com/Rhymen/go-whatsapp"
"github.com/karmanyaahm/groupme"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
@ -158,19 +157,19 @@ type UsernameTemplateArgs struct {
UserID id.UserID
}
func (bc BridgeConfig) FormatDisplayname(contact whatsapp.Contact) (string, int8) {
func (bc BridgeConfig) FormatDisplayname(contact groupme.User) (string, int8) {
var buf bytes.Buffer
if index := strings.IndexRune(contact.Jid, '@'); index > 0 {
contact.Jid = "+" + contact.Jid[:index]
if index := strings.IndexRune(contact.ID.String(), '@'); index > 0 {
contact.ID = groupme.ID("+" + contact.ID.String()[:index])
}
bc.displaynameTemplate.Execute(&buf, contact)
var quality int8
switch {
case len(contact.Notify) > 0:
case len(contact.Name) > 0:
quality = 3
case len(contact.Name) > 0 || len(contact.Short) > 0:
case len(contact.Name) > 0 || len(contact.Name) > 0:
quality = 2
case len(contact.Jid) > 0:
case len(contact.ID) > 0:
quality = 1
default:
quality = 0

View File

@ -52,8 +52,9 @@ func New(dbType string, uri string, baseLog log.Logger) (*Database, error) {
} else {
conn = postgres.Open(uri)
}
print("no")
gdb, err := gorm.Open(conn, &gorm.Config{
// Logger: logger.Default.LogMode(logger.Info),
// Logger: baseLog,
NamingStrategy: schema.NamingStrategy{
NameReplacer: strings.NewReplacer("JID", "Jid", "MXID", "Mxid"),

View File

@ -17,9 +17,9 @@
package database
import (
"github.com/karmanyaahm/groupme"
log "maunium.net/go/maulogger/v2"
"maunium.net/go/mautrix-whatsapp/groupmeExt"
"maunium.net/go/mautrix-whatsapp/types"
"maunium.net/go/mautrix/id"
)
@ -76,12 +76,12 @@ type Message struct {
db *Database
log log.Logger
Chat PortalKey `gorm:"primaryKey;embedded;embeddedPrefix:chat_"`
JID types.GroupMeID `gorm:"primaryKey"`
MXID id.EventID `gorm:"unique;notNull"`
Sender types.GroupMeID `gorm:"notNull"`
Timestamp uint64 `gorm:"notNull;default:0"`
Content *groupme.Message `gorm:"type:TEXT;notNull"`
Chat PortalKey `gorm:"primaryKey;embedded;embeddedPrefix:chat_"`
JID types.GroupMeID `gorm:"primaryKey"`
MXID id.EventID `gorm:"unique;notNull"`
Sender types.GroupMeID `gorm:"notNull"`
Timestamp uint64 `gorm:"notNull;default:0"`
Content *groupmeExt.Message `gorm:"type:TEXT;notNull"`
// Portal Portal `gorm:"foreignKey:JID;"` //`gorm:"foreignKey:Chat.Receiver,Chat.JID;references:jid,receiver;constraint:onDelete:CASCADE;"`TODO
}
@ -124,13 +124,13 @@ type Message struct {
func (msg *Message) Insert() {
ans := msg.db.Create(&msg)
if ans.Error != nil {
// msg.log.Warnfln("Failed to insert %s@%s: %v", msg.Chat, msg.JID, ans.Error)
msg.log.Warnfln("Failed to insert %s@%s: %v", msg.Chat, msg.JID, ans.Error)
}
}
func (msg *Message) Delete() {
ans := msg.db.Delete(&msg)
if ans.Error != nil {
// msg.log.Warnfln("Failed to delete %s@%s: %v", msg.Chat, msg.JID, ans.Error)
msg.log.Warnfln("Failed to delete %s@%s: %v", msg.Chat, msg.JID, ans.Error)
}
}

View File

@ -44,6 +44,10 @@ func (pq *PuppetQuery) GetAll() (puppets []*Puppet) {
if ans.Error != nil || len(puppets) == 0 {
return nil
}
for _, puppet := range puppets {
puppet.db = pq.db
puppet.log = pq.log
}
// defer rows.Close()
// for rows.Next() {
// puppets = append(puppets, pq.New().Scan(rows))
@ -57,6 +61,8 @@ func (pq *PuppetQuery) Get(jid types.GroupMeID) *Puppet {
if ans.Error != nil || ans.RowsAffected == 0 {
return nil
}
puppet.db = pq.db
puppet.log = pq.log
return &puppet
}
@ -66,6 +72,8 @@ func (pq *PuppetQuery) GetByCustomMXID(mxid id.UserID) *Puppet {
if ans.Error != nil || ans.RowsAffected == 0 {
return nil
}
puppet.db = pq.db
puppet.log = pq.log
return &puppet
}
@ -75,6 +83,10 @@ func (pq *PuppetQuery) GetAllWithCustomMXID() (puppets []*Puppet) {
if ans.Error != nil || len(puppets) != 0 {
return nil
}
for _, puppet := range puppets {
puppet.db = pq.db
puppet.log = pq.log
}
// defer rows.Close()
// for rows.Next() {
// puppets = append(puppets, pq.New().Scan(rows))

View File

@ -153,6 +153,8 @@ func (store *SQLStateStore) FindSharedRooms(userID id.UserID) (rooms []id.RoomID
rows, err := store.db.Table("mx_user_profile").Select("room_id").
Joins("LEFT JOIN portal ON portal.mxid=mx_user_profile.room_id").
Where("user_id = ? AND portal.encrypted=true", userID).Rows()
defer rows.Close()
if err != nil {
store.log.Warnfln("Failed to query shared rooms with %s: %v", userID, err)
return
@ -198,7 +200,7 @@ func (store *SQLStateStore) SetMembership(roomID id.RoomID, userID id.UserID, me
print("weird thing 2 502650285")
print(user.Membership)
ans := store.db.Debug().Clauses(clause.OnConflict{
ans := store.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "room_id"}, {Name: "user_id"}},
DoUpdates: clause.AssignmentColumns([]string{"membership"}),
}).Create(&user)

View File

@ -154,8 +154,9 @@ func (user *User) UpdateLastConnection() {
func (user *User) Update() {
ans := user.db.Save(&user)
if ans.Error != nil {
user.log.Warnfln("Failed to update last connection ts: %v", ans.Error)
user.log.Warnfln("Failed to update user: %v", ans.Error)
}
}
type PortalKeyWithMeta struct {
@ -197,6 +198,7 @@ func (user *User) SetPortalKeys(newKeys []PortalKeyWithMeta) error {
}
}
println("portalkey transaction complete")
return tx.Commit().Error
}

View File

@ -288,29 +288,30 @@ func init() {
func (portal *Portal) markHandled(source *User, message *groupme.Message, mxid id.EventID) {
print("handle message")
// msg := portal.bridge.DB.Message.New()
// msg.Chat = portal.Key
// msg.JID = message.GetKey().GetId()
// msg.MXID = mxid
// msg.Timestamp = message.GetMessageTimestamp()
// if message.GetKey().GetFromMe() {
// msg.Sender = source.JID
// } else if portal.IsPrivateChat() {
// msg.Sender = portal.Key.JID
// } else {
// msg.Sender = message.GetKey().GetParticipant()
// if len(msg.Sender) == 0 {
// msg.Sender = message.GetParticipant()
// }
// }
// msg.Content = message.Message
// msg.Insert()
msg := portal.bridge.DB.Message.New()
msg.Chat = portal.Key
msg.JID = message.ID.String()
msg.MXID = mxid
msg.Timestamp = uint64(message.CreatedAt.ToTime().Unix())
if message.UserID.String() == source.JID {
msg.Sender = source.JID
} else if portal.IsPrivateChat() {
msg.Sender = portal.Key.JID
} else {
msg.Sender = message.ID.String()
if len(msg.Sender) == 0 {
println("AAAAAAAAAAAAAAAAAAAAAAAAAAIDK")
msg.Sender = message.SenderID.String()
}
}
msg.Content = &groupmeExt.Message{Message: *message}
msg.Insert()
// portal.recentlyHandledLock.Lock()
// index := portal.recentlyHandledIndex
// portal.recentlyHandledIndex = (portal.recentlyHandledIndex + 1) % recentlyHandledLength
// portal.recentlyHandledLock.Unlock()
// portal.recentlyHandled[index] = msg.JID
portal.recentlyHandledLock.Lock()
index := portal.recentlyHandledIndex
portal.recentlyHandledIndex = (portal.recentlyHandledIndex + 1) % recentlyHandledLength
portal.recentlyHandledLock.Unlock()
portal.recentlyHandled[index] = groupme.ID(msg.JID)
}
func (portal *Portal) getMessageIntent(user *User, info *groupme.Message) *appservice.IntentAPI {
@ -703,10 +704,13 @@ func (portal *Portal) BackfillHistory(user *User, lastMessageTime uint64) error
endBackfill := portal.beginBackfill()
defer endBackfill()
println("hi")
lastMessage := portal.bridge.DB.Message.GetLastInChat(portal.Key)
fmt.Println(lastMessage)
if lastMessage == nil {
return nil
}
println(lastMessage.Timestamp, lastMessageTime)
if lastMessage.Timestamp >= lastMessageTime {
portal.log.Debugln("Not backfilling: no new messages")
return nil

View File

@ -21,7 +21,7 @@ import (
"regexp"
"strings"
"github.com/Rhymen/go-whatsapp"
"github.com/karmanyaahm/groupme"
log "maunium.net/go/maulogger/v2"
"maunium.net/go/mautrix/appservice"
@ -232,7 +232,7 @@ func (puppet *Puppet) UpdateAvatar(source *User, avatar *whatsappExt.ProfilePicI
return true
}
func (puppet *Puppet) UpdateName(source *User, contact whatsapp.Contact) bool {
func (puppet *Puppet) UpdateName(source *User, contact groupme.User) bool {
newName, quality := puppet.bridge.Config.Bridge.FormatDisplayname(contact)
if puppet.Displayname != newName && quality >= puppet.NameQuality {
err := puppet.DefaultIntent().SetDisplayName(newName)
@ -284,20 +284,21 @@ func (puppet *Puppet) updatePortalName() {
})
}
func (puppet *Puppet) Sync(source *User, contact whatsapp.Contact) {
// err := puppet.DefaultIntent().EnsureRegistered()
// if err != nil {
// puppet.log.Errorln("Failed to ensure registered:", err)
// }
func (puppet *Puppet) Sync(source *User, contact groupme.User) {
err := puppet.DefaultIntent().EnsureRegistered()
if err != nil {
puppet.log.Errorln("Failed to ensure registered:", err)
}
// if contact.Jid == source.JID {
// contact.Notify = source.Conn.Info.Pushname
// }
if contact.ID.String() == source.JID {
//TODO What is this
// contact.Notify = source.Conn.Info.Pushname
}
// update := false
// update = puppet.UpdateName(source, contact) || update
// update = puppet.UpdateAvatar(source, nil) || update
// if update {
// puppet.Update()
// }
update := false
update = puppet.UpdateName(source, contact) || update
update = puppet.UpdateAvatar(source, nil) || update
if update {
puppet.Update()
}
}

453
user.go
View File

@ -18,20 +18,16 @@ package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"sort"
"strings"
"sync"
"time"
log "maunium.net/go/maulogger/v2"
"github.com/Rhymen/go-whatsapp"
waBinary "github.com/Rhymen/go-whatsapp/binary"
waProto "github.com/Rhymen/go-whatsapp/binary/proto"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/event"
@ -154,10 +150,10 @@ func (bridge *Bridge) loadDBUser(dbUser *database.User, mxid *id.UserID) *User {
}
func (user *User) GetPortals() []*Portal {
user.bridge.portalsLock.Lock()
keys := user.User.GetPortalKeys()
portals := make([]*Portal, len(keys))
user.bridge.portalsLock.Lock()
for i, key := range keys {
portal, ok := user.bridge.portalsByJID[key]
if !ok {
@ -237,6 +233,7 @@ func (user *User) Connect() bool {
} else if len(user.Token) == 0 {
return false
}
user.log.Debugln("Connecting to WhatsApp")
timeout := time.Duration(user.bridge.Config.Bridge.ConnectionTimeout)
if timeout == 0 {
@ -244,6 +241,7 @@ func (user *User) Connect() bool {
}
conn := groupme.NewPushSubscription(context.TODO())
user.Conn = &conn
user.Conn.StartListening(context.TODO())
// if err != nil {
// user.log.Errorln("Failed to connect to WhatsApp:", err)
// user.sendMarkdownBridgeAlert("\u26a0 Failed to connect to WhatsApp server. " +
@ -253,7 +251,7 @@ func (user *User) Connect() bool {
// user.Conn = whatsappExt.ExtendConn(conn)
// _ = user.Conn.SetClientName(user.bridge.Config.WhatsApp.OSName, user.bridge.Config.WhatsApp.BrowserName, WAVersion)
// user.log.Debugln("WhatsApp connection successful")
// user.Conn.AddHandler(user)
user.Conn.AddHandler(user)
//TODO: typing notification?
return user.RestoreSession()
@ -280,7 +278,10 @@ func (user *User) RestoreSession() bool {
// return false
// }
user.Conn.SubscribeToUser(context.TODO(), groupme.ID(user.JID), user.Token)
err := user.Conn.SubscribeToUser(context.TODO(), groupme.ID(user.JID), user.Token)
if err != nil {
fmt.Println(err)
}
//TODO: typing notifics
user.ConnectionErrors = 0
//user.SetSession(&sess)
@ -469,12 +470,14 @@ func (user *User) intPostLogin() {
defer user.syncWait.Done()
user.lastReconnection = time.Now().Unix()
user.Client = groupmeExt.NewClient(user.Token)
myuser, err := user.Client.MyUser(context.TODO())
if err != nil {
log.Fatal(err) //TODO
if len(user.JID) == 0 {
myuser, err := user.Client.MyUser(context.TODO())
if err != nil {
log.Fatal(err) //TODO
}
user.JID = myuser.ID.String()
user.Update()
}
user.JID = myuser.ID.String()
user.Update()
user.createCommunity()
user.tryAutomaticDoublePuppeting()
@ -550,7 +553,7 @@ func (user *User) syncPortals(chatMap map[string]groupme.Group, createAll bool)
chats = append(chats, Chat{
Portal: portal,
LastMessageTime: uint64(time.Now().Unix()),
LastMessageTime: uint64(chat.UpdatedAt.ToTime().Unix()),
Group: chat,
})
var inCommunity, ok bool
@ -564,6 +567,7 @@ func (user *User) syncPortals(chatMap map[string]groupme.Group, createAll bool)
portalKeys = append(portalKeys, database.PortalKeyWithMeta{PortalKey: portal.Key, InCommunity: inCommunity})
}
user.log.Infoln("Read chat list, updating user-portal mapping")
err := user.SetPortalKeys(portalKeys)
if err != nil {
user.log.Warnln("Failed to update user-portal mapping:", err)
@ -793,6 +797,13 @@ func (user *User) handleMessageLoop() {
select {
case msg := <-user.messageOutput:
user.bridge.Metrics.TrackBufferLength(user.MXID, len(user.messageOutput))
puppet := user.bridge.GetPuppetByJID(msg.data.UserID.String())
if puppet != nil {
puppet.Sync(user, groupme.User{
ID: msg.data.ID,
Name: msg.data.Name,
}) //TODO: add params or docs?
}
user.GetPortalByJID(msg.chat).messages <- msg
case <-user.syncStart:
user.log.Debugln("Processing of incoming messages is locked")
@ -804,33 +815,33 @@ func (user *User) handleMessageLoop() {
}
}
func (user *User) HandleNewContact(contact whatsapp.Contact) {
user.log.Debugfln("Contact message: %+v", contact)
go func() {
if strings.HasSuffix(contact.Jid, whatsappExt.OldUserSuffix) {
contact.Jid = strings.Replace(contact.Jid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, -1)
}
puppet := user.bridge.GetPuppetByJID(contact.Jid)
puppet.UpdateName(user, contact)
}()
}
//func (user *User) HandleNewContact(contact whatsapp.Contact) {
// user.log.Debugfln("Contact message: %+v", contact)
// go func() {
// if strings.HasSuffix(contact.Jid, whatsappExt.OldUserSuffix) {
// contact.Jid = strings.Replace(contact.Jid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, -1)
// }
// puppet := user.bridge.GetPuppetByJID(contact.Jid)
// puppet.UpdateName(user, contact)
// }()
//}
func (user *User) HandleBatteryMessage(battery whatsapp.BatteryMessage) {
user.log.Debugfln("Battery message: %+v", battery)
var notice string
if !battery.Plugged && battery.Percentage < 15 && user.batteryWarningsSent < 1 {
notice = fmt.Sprintf("Phone battery low (%d %% remaining)", battery.Percentage)
user.batteryWarningsSent = 1
} else if !battery.Plugged && battery.Percentage < 5 && user.batteryWarningsSent < 2 {
notice = fmt.Sprintf("Phone battery very low (%d %% remaining)", battery.Percentage)
user.batteryWarningsSent = 2
} else if battery.Percentage > 15 || battery.Plugged {
user.batteryWarningsSent = 0
}
if notice != "" {
go user.sendBridgeNotice("%s", notice)
}
}
//func (user *User) HandleBatteryMessage(battery whatsapp.BatteryMessage) {
// user.log.Debugfln("Battery message: %+v", battery)
// var notice string
// if !battery.Plugged && battery.Percentage < 15 && user.batteryWarningsSent < 1 {
// notice = fmt.Sprintf("Phone battery low (%d %% remaining)", battery.Percentage)
// user.batteryWarningsSent = 1
// } else if !battery.Plugged && battery.Percentage < 5 && user.batteryWarningsSent < 2 {
// notice = fmt.Sprintf("Phone battery very low (%d %% remaining)", battery.Percentage)
// user.batteryWarningsSent = 2
// } else if battery.Percentage > 15 || battery.Plugged {
// user.batteryWarningsSent = 0
// }
// if notice != "" {
// go user.sendBridgeNotice("%s", notice)
// }
//}
func (user *User) HandleTextMessage(message groupme.Message) {
user.messageInput <- PortalMessage{message.GroupID.String(), user, &message, uint64(message.CreatedAt.ToTime().Unix())}
@ -909,191 +920,191 @@ type FakeMessage struct {
// }
//}
func (user *User) HandlePresence(info whatsappExt.Presence) {
puppet := user.bridge.GetPuppetByJID(info.SenderJID)
switch info.Status {
case whatsapp.PresenceUnavailable:
_ = puppet.DefaultIntent().SetPresence("offline")
case whatsapp.PresenceAvailable:
if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() {
portal := user.bridge.GetPortalByMXID(puppet.typingIn)
_, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0)
puppet.typingIn = ""
puppet.typingAt = 0
} else {
_ = puppet.DefaultIntent().SetPresence("online")
}
case whatsapp.PresenceComposing:
portal := user.GetPortalByJID(info.JID)
if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() {
if puppet.typingIn == portal.MXID {
return
}
_, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0)
}
puppet.typingIn = portal.MXID
puppet.typingAt = time.Now().Unix()
_, _ = puppet.IntentFor(portal).UserTyping(portal.MXID, true, 15*1000)
}
}
//func (user *User) HandlePresence(info whatsappExt.Presence) {
// puppet := user.bridge.GetPuppetByJID(info.SenderJID)
// switch info.Status {
// case whatsapp.PresenceUnavailable:
// _ = puppet.DefaultIntent().SetPresence("offline")
// case whatsapp.PresenceAvailable:
// if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() {
// portal := user.bridge.GetPortalByMXID(puppet.typingIn)
// _, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0)
// puppet.typingIn = ""
// puppet.typingAt = 0
// } else {
// _ = puppet.DefaultIntent().SetPresence("online")
// }
// case whatsapp.PresenceComposing:
// portal := user.GetPortalByJID(info.JID)
// if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() {
// if puppet.typingIn == portal.MXID {
// return
// }
// _, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0)
// }
// puppet.typingIn = portal.MXID
// puppet.typingAt = time.Now().Unix()
// _, _ = puppet.IntentFor(portal).UserTyping(portal.MXID, true, 15*1000)
// }
//}
//
//func (user *User) HandleMsgInfo(info whatsappExt.MsgInfo) {
// if (info.Command == whatsappExt.MsgInfoCommandAck || info.Command == whatsappExt.MsgInfoCommandAcks) && info.Acknowledgement == whatsappExt.AckMessageRead {
// portal := user.GetPortalByJID(info.ToJID)
// if len(portal.MXID) == 0 {
// return
// }
//
// go func() {
// intent := user.bridge.GetPuppetByJID(info.SenderJID).IntentFor(portal)
// for _, msgID := range info.IDs {
// msg := user.bridge.DB.Message.GetByJID(portal.Key, msgID)
// 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) HandleMsgInfo(info whatsappExt.MsgInfo) {
if (info.Command == whatsappExt.MsgInfoCommandAck || info.Command == whatsappExt.MsgInfoCommandAcks) && info.Acknowledgement == whatsappExt.AckMessageRead {
portal := user.GetPortalByJID(info.ToJID)
if len(portal.MXID) == 0 {
return
}
//func (user *User) HandleReceivedMessage(received whatsapp.ReceivedMessage) {
// if received.Type == "read" {
// user.markSelfRead(received.Jid, received.Index)
// } else {
// user.log.Debugfln("Unknown received message type: %+v", received)
// }
//}
//
//func (user *User) HandleReadMessage(read whatsapp.ReadMessage) {
// user.log.Debugfln("Received chat read message: %+v", read)
// user.markSelfRead(read.Jid, "")
//}
//
//func (user *User) markSelfRead(jid, messageID string) {
// if strings.HasSuffix(jid, whatsappExt.OldUserSuffix) {
// jid = strings.Replace(jid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, -1)
// }
// puppet := user.bridge.GetPuppetByJID(user.JID)
// if puppet == nil {
// return
// }
// intent := puppet.CustomIntent()
// if intent == nil {
// return
// }
// portal := user.GetPortalByJID(jid)
// if portal == nil {
// return
// }
// var message *database.Message
// if messageID == "" {
// message = user.bridge.DB.Message.GetLastInChat(portal.Key)
// if message == nil {
// return
// }
// 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 {
// 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 := intent.MarkRead(portal.MXID, message.MXID)
// if err != nil {
// user.log.Warnfln("Failed to bridge own read receipt in %s: %v", jid, err)
// }
//}
//
//func (user *User) HandleCommand(cmd whatsappExt.Command) {
// switch cmd.Type {
// case whatsappExt.CommandPicture:
// if strings.HasSuffix(cmd.JID, whatsappExt.NewUserSuffix) {
// puppet := user.bridge.GetPuppetByJID(cmd.JID)
// go puppet.UpdateAvatar(user, cmd.ProfilePicInfo)
// } else {
// portal := user.GetPortalByJID(cmd.JID)
// go portal.UpdateAvatar(user, cmd.ProfilePicInfo, true)
// }
// case whatsappExt.CommandDisconnect:
// user.cleanDisconnection = true
// if cmd.Kind == "replaced" {
// go user.sendMarkdownBridgeAlert("\u26a0 Your WhatsApp connection was closed by the server because you opened another WhatsApp Web client.\n\n" +
// "Use the `reconnect` command to disconnect the other client and resume bridging.")
// } else {
// user.log.Warnln("Unknown kind of disconnect:", string(cmd.Raw))
// go user.sendMarkdownBridgeAlert("\u26a0 Your WhatsApp connection was closed by the server (reason code: %s).\n\n"+
// "Use the `reconnect` command to reconnect.", cmd.Kind)
// }
// }
//}
//
//func (user *User) HandleChatUpdate(cmd whatsappExt.ChatUpdate) {
// if cmd.Command != whatsappExt.ChatUpdateCommandAction {
// return
// }
//
// portal := user.GetPortalByJID(cmd.JID)
// if len(portal.MXID) == 0 {
// if cmd.Data.Action == whatsappExt.ChatActionIntroduce || cmd.Data.Action == whatsappExt.ChatActionCreate {
// go func() {
// err := portal.CreateMatrixRoom(user)
// if err != nil {
// user.log.Errorln("Failed to create portal room after receiving join event:", err)
// }
// }()
// }
// return
// }
//
// switch cmd.Data.Action {
// case whatsappExt.ChatActionNameChange:
// go portal.UpdateName(cmd.Data.NameChange.Name, cmd.Data.SenderJID, true)
// case whatsappExt.ChatActionAddTopic:
// go portal.UpdateTopic(cmd.Data.AddTopic.Topic, cmd.Data.SenderJID, true)
// case whatsappExt.ChatActionRemoveTopic:
// go portal.UpdateTopic("", cmd.Data.SenderJID, true)
// case whatsappExt.ChatActionPromote:
// go portal.ChangeAdminStatus(cmd.Data.UserChange.JIDs, true)
// case whatsappExt.ChatActionDemote:
// go portal.ChangeAdminStatus(cmd.Data.UserChange.JIDs, false)
// case whatsappExt.ChatActionAnnounce:
// go portal.RestrictMessageSending(cmd.Data.Announce)
// case whatsappExt.ChatActionRestrict:
// go portal.RestrictMetadataChanges(cmd.Data.Restrict)
// case whatsappExt.ChatActionRemove:
// go portal.HandleWhatsAppKick(cmd.Data.SenderJID, cmd.Data.UserChange.JIDs)
// case whatsappExt.ChatActionAdd:
// go portal.HandleWhatsAppInvite(cmd.Data.SenderJID, cmd.Data.UserChange.JIDs)
// //case whatsappExt.ChatActionIntroduce:
// // if cmd.Data.SenderJID != "unknown" {
// // go portal.Sync(user, whatsapp.Contact{Jid: portal.Key.JID})
// // }
// }
//}
go func() {
intent := user.bridge.GetPuppetByJID(info.SenderJID).IntentFor(portal)
for _, msgID := range info.IDs {
msg := user.bridge.DB.Message.GetByJID(portal.Key, msgID)
if msg == nil {
continue
}
//func (user *User) HandleJsonMessage(message string) {
// var msg json.RawMessage
// err := json.Unmarshal([]byte(message), &msg)
// if err != nil {
// return
// }
// user.log.Debugln("JSON message:", message)
// user.updateLastConnectionIfNecessary()
//}
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) HandleReceivedMessage(received whatsapp.ReceivedMessage) {
if received.Type == "read" {
user.markSelfRead(received.Jid, received.Index)
} else {
user.log.Debugfln("Unknown received message type: %+v", received)
}
}
func (user *User) HandleReadMessage(read whatsapp.ReadMessage) {
user.log.Debugfln("Received chat read message: %+v", read)
user.markSelfRead(read.Jid, "")
}
func (user *User) markSelfRead(jid, messageID string) {
if strings.HasSuffix(jid, whatsappExt.OldUserSuffix) {
jid = strings.Replace(jid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, -1)
}
puppet := user.bridge.GetPuppetByJID(user.JID)
if puppet == nil {
return
}
intent := puppet.CustomIntent()
if intent == nil {
return
}
portal := user.GetPortalByJID(jid)
if portal == nil {
return
}
var message *database.Message
if messageID == "" {
message = user.bridge.DB.Message.GetLastInChat(portal.Key)
if message == nil {
return
}
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 {
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 := intent.MarkRead(portal.MXID, message.MXID)
if err != nil {
user.log.Warnfln("Failed to bridge own read receipt in %s: %v", jid, err)
}
}
func (user *User) HandleCommand(cmd whatsappExt.Command) {
switch cmd.Type {
case whatsappExt.CommandPicture:
if strings.HasSuffix(cmd.JID, whatsappExt.NewUserSuffix) {
puppet := user.bridge.GetPuppetByJID(cmd.JID)
go puppet.UpdateAvatar(user, cmd.ProfilePicInfo)
} else {
portal := user.GetPortalByJID(cmd.JID)
go portal.UpdateAvatar(user, cmd.ProfilePicInfo, true)
}
case whatsappExt.CommandDisconnect:
user.cleanDisconnection = true
if cmd.Kind == "replaced" {
go user.sendMarkdownBridgeAlert("\u26a0 Your WhatsApp connection was closed by the server because you opened another WhatsApp Web client.\n\n" +
"Use the `reconnect` command to disconnect the other client and resume bridging.")
} else {
user.log.Warnln("Unknown kind of disconnect:", string(cmd.Raw))
go user.sendMarkdownBridgeAlert("\u26a0 Your WhatsApp connection was closed by the server (reason code: %s).\n\n"+
"Use the `reconnect` command to reconnect.", cmd.Kind)
}
}
}
func (user *User) HandleChatUpdate(cmd whatsappExt.ChatUpdate) {
if cmd.Command != whatsappExt.ChatUpdateCommandAction {
return
}
portal := user.GetPortalByJID(cmd.JID)
if len(portal.MXID) == 0 {
if cmd.Data.Action == whatsappExt.ChatActionIntroduce || cmd.Data.Action == whatsappExt.ChatActionCreate {
go func() {
err := portal.CreateMatrixRoom(user)
if err != nil {
user.log.Errorln("Failed to create portal room after receiving join event:", err)
}
}()
}
return
}
switch cmd.Data.Action {
case whatsappExt.ChatActionNameChange:
go portal.UpdateName(cmd.Data.NameChange.Name, cmd.Data.SenderJID, true)
case whatsappExt.ChatActionAddTopic:
go portal.UpdateTopic(cmd.Data.AddTopic.Topic, cmd.Data.SenderJID, true)
case whatsappExt.ChatActionRemoveTopic:
go portal.UpdateTopic("", cmd.Data.SenderJID, true)
case whatsappExt.ChatActionPromote:
go portal.ChangeAdminStatus(cmd.Data.UserChange.JIDs, true)
case whatsappExt.ChatActionDemote:
go portal.ChangeAdminStatus(cmd.Data.UserChange.JIDs, false)
case whatsappExt.ChatActionAnnounce:
go portal.RestrictMessageSending(cmd.Data.Announce)
case whatsappExt.ChatActionRestrict:
go portal.RestrictMetadataChanges(cmd.Data.Restrict)
case whatsappExt.ChatActionRemove:
go portal.HandleWhatsAppKick(cmd.Data.SenderJID, cmd.Data.UserChange.JIDs)
case whatsappExt.ChatActionAdd:
go portal.HandleWhatsAppInvite(cmd.Data.SenderJID, cmd.Data.UserChange.JIDs)
//case whatsappExt.ChatActionIntroduce:
// if cmd.Data.SenderJID != "unknown" {
// go portal.Sync(user, whatsapp.Contact{Jid: portal.Key.JID})
// }
}
}
func (user *User) HandleJsonMessage(message string) {
var msg json.RawMessage
err := json.Unmarshal([]byte(message), &msg)
if err != nil {
return
}
user.log.Debugln("JSON message:", message)
user.updateLastConnectionIfNecessary()
}
func (user *User) HandleRawMessage(message *waProto.WebMessageInfo) {
user.updateLastConnectionIfNecessary()
}
func (user *User) HandleUnknownBinaryNode(node *waBinary.Node) {
user.log.Debugfln("Unknown binary message: %+v", node)
}
//func (user *User) HandleRawMessage(message *waProto.WebMessageInfo) {
// user.updateLastConnectionIfNecessary()
//}
//
//func (user *User) HandleUnknownBinaryNode(node *waBinary.Node) {
// user.log.Debugfln("Unknown binary message: %+v", node)
//}
func (user *User) NeedsRelaybot(portal *Portal) bool {
return !user.HasSession() || !user.IsInPortal(portal.Key)