From f1c093896e56ae8d47dbab5a0031984fff2e9772 Mon Sep 17 00:00:00 2001 From: Karmanyaah Malhotra Date: Sun, 21 Feb 2021 22:46:17 -0500 Subject: [PATCH] kinda --- config/bridge.go | 15 +- database/database.go | 3 +- database/message.go | 18 +- database/puppet.go | 12 ++ database/statestore.go | 4 +- database/user.go | 4 +- portal.go | 48 +++-- puppet.go | 33 +-- user.go | 453 +++++++++++++++++++++-------------------- 9 files changed, 311 insertions(+), 279 deletions(-) diff --git a/config/bridge.go b/config/bridge.go index 696d1cb..79c3079 100644 --- a/config/bridge.go +++ b/config/bridge.go @@ -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 diff --git a/database/database.go b/database/database.go index a7bd11b..06b946f 100644 --- a/database/database.go +++ b/database/database.go @@ -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"), diff --git a/database/message.go b/database/message.go index f0d7cef..3cf4781 100644 --- a/database/message.go +++ b/database/message.go @@ -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) } } diff --git a/database/puppet.go b/database/puppet.go index a7d0485..9896232 100644 --- a/database/puppet.go +++ b/database/puppet.go @@ -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)) diff --git a/database/statestore.go b/database/statestore.go index bbea364..0d807d1 100644 --- a/database/statestore.go +++ b/database/statestore.go @@ -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) diff --git a/database/user.go b/database/user.go index 174e286..98dfe28 100644 --- a/database/user.go +++ b/database/user.go @@ -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 } diff --git a/portal.go b/portal.go index c80b515..c38f898 100644 --- a/portal.go +++ b/portal.go @@ -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 diff --git a/puppet.go b/puppet.go index 28a4500..dee113f 100644 --- a/puppet.go +++ b/puppet.go @@ -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() + } } diff --git a/user.go b/user.go index 609946c..78bb0e7 100644 --- a/user.go +++ b/user.go @@ -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)