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

View File

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

View File

@ -17,9 +17,9 @@
package database package database
import ( import (
"github.com/karmanyaahm/groupme"
log "maunium.net/go/maulogger/v2" log "maunium.net/go/maulogger/v2"
"maunium.net/go/mautrix-whatsapp/groupmeExt"
"maunium.net/go/mautrix-whatsapp/types" "maunium.net/go/mautrix-whatsapp/types"
"maunium.net/go/mautrix/id" "maunium.net/go/mautrix/id"
) )
@ -76,12 +76,12 @@ type Message struct {
db *Database db *Database
log log.Logger log log.Logger
Chat PortalKey `gorm:"primaryKey;embedded;embeddedPrefix:chat_"` Chat PortalKey `gorm:"primaryKey;embedded;embeddedPrefix:chat_"`
JID types.GroupMeID `gorm:"primaryKey"` JID types.GroupMeID `gorm:"primaryKey"`
MXID id.EventID `gorm:"unique;notNull"` MXID id.EventID `gorm:"unique;notNull"`
Sender types.GroupMeID `gorm:"notNull"` Sender types.GroupMeID `gorm:"notNull"`
Timestamp uint64 `gorm:"notNull;default:0"` Timestamp uint64 `gorm:"notNull;default:0"`
Content *groupme.Message `gorm:"type:TEXT;notNull"` 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 // 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() { func (msg *Message) Insert() {
ans := msg.db.Create(&msg) ans := msg.db.Create(&msg)
if ans.Error != nil { 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() { func (msg *Message) Delete() {
ans := msg.db.Delete(&msg) ans := msg.db.Delete(&msg)
if ans.Error != nil { 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 { if ans.Error != nil || len(puppets) == 0 {
return nil return nil
} }
for _, puppet := range puppets {
puppet.db = pq.db
puppet.log = pq.log
}
// defer rows.Close() // defer rows.Close()
// for rows.Next() { // for rows.Next() {
// puppets = append(puppets, pq.New().Scan(rows)) // 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 { if ans.Error != nil || ans.RowsAffected == 0 {
return nil return nil
} }
puppet.db = pq.db
puppet.log = pq.log
return &puppet return &puppet
} }
@ -66,6 +72,8 @@ func (pq *PuppetQuery) GetByCustomMXID(mxid id.UserID) *Puppet {
if ans.Error != nil || ans.RowsAffected == 0 { if ans.Error != nil || ans.RowsAffected == 0 {
return nil return nil
} }
puppet.db = pq.db
puppet.log = pq.log
return &puppet return &puppet
} }
@ -75,6 +83,10 @@ func (pq *PuppetQuery) GetAllWithCustomMXID() (puppets []*Puppet) {
if ans.Error != nil || len(puppets) != 0 { if ans.Error != nil || len(puppets) != 0 {
return nil return nil
} }
for _, puppet := range puppets {
puppet.db = pq.db
puppet.log = pq.log
}
// defer rows.Close() // defer rows.Close()
// for rows.Next() { // for rows.Next() {
// puppets = append(puppets, pq.New().Scan(rows)) // 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"). rows, err := store.db.Table("mx_user_profile").Select("room_id").
Joins("LEFT JOIN portal ON portal.mxid=mx_user_profile.room_id"). Joins("LEFT JOIN portal ON portal.mxid=mx_user_profile.room_id").
Where("user_id = ? AND portal.encrypted=true", userID).Rows() Where("user_id = ? AND portal.encrypted=true", userID).Rows()
defer rows.Close()
if err != nil { if err != nil {
store.log.Warnfln("Failed to query shared rooms with %s: %v", userID, err) store.log.Warnfln("Failed to query shared rooms with %s: %v", userID, err)
return return
@ -198,7 +200,7 @@ func (store *SQLStateStore) SetMembership(roomID id.RoomID, userID id.UserID, me
print("weird thing 2 502650285") print("weird thing 2 502650285")
print(user.Membership) 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"}}, Columns: []clause.Column{{Name: "room_id"}, {Name: "user_id"}},
DoUpdates: clause.AssignmentColumns([]string{"membership"}), DoUpdates: clause.AssignmentColumns([]string{"membership"}),
}).Create(&user) }).Create(&user)

View File

@ -154,8 +154,9 @@ func (user *User) UpdateLastConnection() {
func (user *User) Update() { func (user *User) Update() {
ans := user.db.Save(&user) ans := user.db.Save(&user)
if ans.Error != nil { 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 { type PortalKeyWithMeta struct {
@ -197,6 +198,7 @@ func (user *User) SetPortalKeys(newKeys []PortalKeyWithMeta) error {
} }
} }
println("portalkey transaction complete")
return tx.Commit().Error return tx.Commit().Error
} }

View File

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

View File

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

453
user.go
View File

@ -18,20 +18,16 @@ package main
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"sort" "sort"
"strings"
"sync" "sync"
"time" "time"
log "maunium.net/go/maulogger/v2" log "maunium.net/go/maulogger/v2"
"github.com/Rhymen/go-whatsapp" "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"
"maunium.net/go/mautrix/event" "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 { func (user *User) GetPortals() []*Portal {
user.bridge.portalsLock.Lock()
keys := user.User.GetPortalKeys() keys := user.User.GetPortalKeys()
portals := make([]*Portal, len(keys)) portals := make([]*Portal, len(keys))
user.bridge.portalsLock.Lock()
for i, key := range keys { for i, key := range keys {
portal, ok := user.bridge.portalsByJID[key] portal, ok := user.bridge.portalsByJID[key]
if !ok { if !ok {
@ -237,6 +233,7 @@ func (user *User) Connect() bool {
} else if len(user.Token) == 0 { } else if len(user.Token) == 0 {
return false return false
} }
user.log.Debugln("Connecting to WhatsApp") user.log.Debugln("Connecting to WhatsApp")
timeout := time.Duration(user.bridge.Config.Bridge.ConnectionTimeout) timeout := time.Duration(user.bridge.Config.Bridge.ConnectionTimeout)
if timeout == 0 { if timeout == 0 {
@ -244,6 +241,7 @@ func (user *User) Connect() bool {
} }
conn := groupme.NewPushSubscription(context.TODO()) conn := groupme.NewPushSubscription(context.TODO())
user.Conn = &conn user.Conn = &conn
user.Conn.StartListening(context.TODO())
// if err != nil { // if err != nil {
// user.log.Errorln("Failed to connect to WhatsApp:", err) // user.log.Errorln("Failed to connect to WhatsApp:", err)
// user.sendMarkdownBridgeAlert("\u26a0 Failed to connect to WhatsApp server. " + // 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 = whatsappExt.ExtendConn(conn)
// _ = user.Conn.SetClientName(user.bridge.Config.WhatsApp.OSName, user.bridge.Config.WhatsApp.BrowserName, WAVersion) // _ = user.Conn.SetClientName(user.bridge.Config.WhatsApp.OSName, user.bridge.Config.WhatsApp.BrowserName, WAVersion)
// user.log.Debugln("WhatsApp connection successful") // user.log.Debugln("WhatsApp connection successful")
// user.Conn.AddHandler(user) user.Conn.AddHandler(user)
//TODO: typing notification? //TODO: typing notification?
return user.RestoreSession() return user.RestoreSession()
@ -280,7 +278,10 @@ func (user *User) RestoreSession() bool {
// return false // 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 //TODO: typing notifics
user.ConnectionErrors = 0 user.ConnectionErrors = 0
//user.SetSession(&sess) //user.SetSession(&sess)
@ -469,12 +470,14 @@ func (user *User) intPostLogin() {
defer user.syncWait.Done() defer user.syncWait.Done()
user.lastReconnection = time.Now().Unix() user.lastReconnection = time.Now().Unix()
user.Client = groupmeExt.NewClient(user.Token) user.Client = groupmeExt.NewClient(user.Token)
myuser, err := user.Client.MyUser(context.TODO()) if len(user.JID) == 0 {
if err != nil { myuser, err := user.Client.MyUser(context.TODO())
log.Fatal(err) //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.createCommunity()
user.tryAutomaticDoublePuppeting() user.tryAutomaticDoublePuppeting()
@ -550,7 +553,7 @@ func (user *User) syncPortals(chatMap map[string]groupme.Group, createAll bool)
chats = append(chats, Chat{ chats = append(chats, Chat{
Portal: portal, Portal: portal,
LastMessageTime: uint64(time.Now().Unix()), LastMessageTime: uint64(chat.UpdatedAt.ToTime().Unix()),
Group: chat, Group: chat,
}) })
var inCommunity, ok bool 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}) portalKeys = append(portalKeys, database.PortalKeyWithMeta{PortalKey: portal.Key, InCommunity: inCommunity})
} }
user.log.Infoln("Read chat list, updating user-portal mapping") user.log.Infoln("Read chat list, updating user-portal mapping")
err := user.SetPortalKeys(portalKeys) err := user.SetPortalKeys(portalKeys)
if err != nil { if err != nil {
user.log.Warnln("Failed to update user-portal mapping:", err) user.log.Warnln("Failed to update user-portal mapping:", err)
@ -793,6 +797,13 @@ func (user *User) handleMessageLoop() {
select { select {
case msg := <-user.messageOutput: case msg := <-user.messageOutput:
user.bridge.Metrics.TrackBufferLength(user.MXID, len(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 user.GetPortalByJID(msg.chat).messages <- msg
case <-user.syncStart: case <-user.syncStart:
user.log.Debugln("Processing of incoming messages is locked") user.log.Debugln("Processing of incoming messages is locked")
@ -804,33 +815,33 @@ func (user *User) handleMessageLoop() {
} }
} }
func (user *User) HandleNewContact(contact whatsapp.Contact) { //func (user *User) HandleNewContact(contact whatsapp.Contact) {
user.log.Debugfln("Contact message: %+v", contact) // user.log.Debugfln("Contact message: %+v", contact)
go func() { // go func() {
if strings.HasSuffix(contact.Jid, whatsappExt.OldUserSuffix) { // if strings.HasSuffix(contact.Jid, whatsappExt.OldUserSuffix) {
contact.Jid = strings.Replace(contact.Jid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, -1) // contact.Jid = strings.Replace(contact.Jid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, -1)
} // }
puppet := user.bridge.GetPuppetByJID(contact.Jid) // puppet := user.bridge.GetPuppetByJID(contact.Jid)
puppet.UpdateName(user, contact) // puppet.UpdateName(user, contact)
}() // }()
} //}
func (user *User) HandleBatteryMessage(battery whatsapp.BatteryMessage) { //func (user *User) HandleBatteryMessage(battery whatsapp.BatteryMessage) {
user.log.Debugfln("Battery message: %+v", battery) // user.log.Debugfln("Battery message: %+v", battery)
var notice string // var notice string
if !battery.Plugged && battery.Percentage < 15 && user.batteryWarningsSent < 1 { // if !battery.Plugged && battery.Percentage < 15 && user.batteryWarningsSent < 1 {
notice = fmt.Sprintf("Phone battery low (%d %% remaining)", battery.Percentage) // notice = fmt.Sprintf("Phone battery low (%d %% remaining)", battery.Percentage)
user.batteryWarningsSent = 1 // user.batteryWarningsSent = 1
} else if !battery.Plugged && battery.Percentage < 5 && user.batteryWarningsSent < 2 { // } else if !battery.Plugged && battery.Percentage < 5 && user.batteryWarningsSent < 2 {
notice = fmt.Sprintf("Phone battery very low (%d %% remaining)", battery.Percentage) // notice = fmt.Sprintf("Phone battery very low (%d %% remaining)", battery.Percentage)
user.batteryWarningsSent = 2 // user.batteryWarningsSent = 2
} else if battery.Percentage > 15 || battery.Plugged { // } else if battery.Percentage > 15 || battery.Plugged {
user.batteryWarningsSent = 0 // user.batteryWarningsSent = 0
} // }
if notice != "" { // if notice != "" {
go user.sendBridgeNotice("%s", notice) // go user.sendBridgeNotice("%s", notice)
} // }
} //}
func (user *User) HandleTextMessage(message groupme.Message) { func (user *User) HandleTextMessage(message groupme.Message) {
user.messageInput <- PortalMessage{message.GroupID.String(), user, &message, uint64(message.CreatedAt.ToTime().Unix())} 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) { //func (user *User) HandlePresence(info whatsappExt.Presence) {
puppet := user.bridge.GetPuppetByJID(info.SenderJID) // puppet := user.bridge.GetPuppetByJID(info.SenderJID)
switch info.Status { // switch info.Status {
case whatsapp.PresenceUnavailable: // case whatsapp.PresenceUnavailable:
_ = puppet.DefaultIntent().SetPresence("offline") // _ = puppet.DefaultIntent().SetPresence("offline")
case whatsapp.PresenceAvailable: // case whatsapp.PresenceAvailable:
if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() { // if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() {
portal := user.bridge.GetPortalByMXID(puppet.typingIn) // portal := user.bridge.GetPortalByMXID(puppet.typingIn)
_, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0) // _, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0)
puppet.typingIn = "" // puppet.typingIn = ""
puppet.typingAt = 0 // puppet.typingAt = 0
} else { // } else {
_ = puppet.DefaultIntent().SetPresence("online") // _ = puppet.DefaultIntent().SetPresence("online")
} // }
case whatsapp.PresenceComposing: // case whatsapp.PresenceComposing:
portal := user.GetPortalByJID(info.JID) // portal := user.GetPortalByJID(info.JID)
if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() { // if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() {
if puppet.typingIn == portal.MXID { // if puppet.typingIn == portal.MXID {
return // return
} // }
_, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0) // _, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0)
} // }
puppet.typingIn = portal.MXID // puppet.typingIn = portal.MXID
puppet.typingAt = time.Now().Unix() // puppet.typingAt = time.Now().Unix()
_, _ = puppet.IntentFor(portal).UserTyping(portal.MXID, true, 15*1000) // _, _ = 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) { //func (user *User) HandleReceivedMessage(received whatsapp.ReceivedMessage) {
if (info.Command == whatsappExt.MsgInfoCommandAck || info.Command == whatsappExt.MsgInfoCommandAcks) && info.Acknowledgement == whatsappExt.AckMessageRead { // if received.Type == "read" {
portal := user.GetPortalByJID(info.ToJID) // user.markSelfRead(received.Jid, received.Index)
if len(portal.MXID) == 0 { // } else {
return // 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() { //func (user *User) HandleJsonMessage(message string) {
intent := user.bridge.GetPuppetByJID(info.SenderJID).IntentFor(portal) // var msg json.RawMessage
for _, msgID := range info.IDs { // err := json.Unmarshal([]byte(message), &msg)
msg := user.bridge.DB.Message.GetByJID(portal.Key, msgID) // if err != nil {
if msg == nil { // return
continue // }
} // user.log.Debugln("JSON message:", message)
// user.updateLastConnectionIfNecessary()
//}
err := intent.MarkRead(portal.MXID, msg.MXID) //func (user *User) HandleRawMessage(message *waProto.WebMessageInfo) {
if err != nil { // user.updateLastConnectionIfNecessary()
user.log.Warnln("Failed to mark message %s as read by %s: %v", msg.MXID, info.SenderJID, err) //}
} //
} //func (user *User) HandleUnknownBinaryNode(node *waBinary.Node) {
}() // user.log.Debugfln("Unknown binary message: %+v", node)
} //}
}
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) NeedsRelaybot(portal *Portal) bool { func (user *User) NeedsRelaybot(portal *Portal) bool {
return !user.HasSession() || !user.IsInPortal(portal.Key) return !user.HasSession() || !user.IsInPortal(portal.Key)