From 496d5b4ec7f5f4afae6199f928675d14d18de015 Mon Sep 17 00:00:00 2001 From: Wim Date: Sun, 20 Mar 2022 02:20:54 +0100 Subject: Add whatsappmulti buildflag for whatsapp with multidevice support (whatsapp) --- bridge/whatsapp/helpers.go | 163 ++++++++++++++++++++++++++++++--------------- 1 file changed, 110 insertions(+), 53 deletions(-) (limited to 'bridge/whatsapp/helpers.go') diff --git a/bridge/whatsapp/helpers.go b/bridge/whatsapp/helpers.go index b32372c5..e424387d 100644 --- a/bridge/whatsapp/helpers.go +++ b/bridge/whatsapp/helpers.go @@ -1,12 +1,15 @@ package bwhatsapp import ( + "encoding/gob" + "encoding/json" + "errors" "fmt" + "os" "strings" - "go.mau.fi/whatsmeow/store" - "go.mau.fi/whatsmeow/store/sqlstore" - "go.mau.fi/whatsmeow/types" + qrcodeTerminal "github.com/Baozisoftware/qrcode-terminal-go" + "github.com/Rhymen/go-whatsapp" ) type ProfilePicInfo struct { @@ -15,71 +18,141 @@ type ProfilePicInfo struct { Status int16 `json:"status"` } -func (b *Bwhatsapp) getSenderName(senderJid types.JID) string { - if sender, exists := b.contacts[senderJid]; exists { - if sender.FullName != "" { - return sender.FullName - } - // if user is not in phone contacts - // it is the most obvious scenario unless you sync your phone contacts with some remote updated source - // users can change it in their WhatsApp settings -> profile -> click on Avatar - if sender.PushName != "" { - return sender.PushName - } +func qrFromTerminal(invert bool) chan string { + qr := make(chan string) + + go func() { + terminal := qrcodeTerminal.New() - if sender.FirstName != "" { - return sender.FirstName + if invert { + terminal = qrcodeTerminal.New2(qrcodeTerminal.ConsoleColors.BrightWhite, qrcodeTerminal.ConsoleColors.BrightBlack, qrcodeTerminal.QRCodeRecoveryLevels.Medium) } + + terminal.Get(<-qr).Print() + }() + + return qr +} + +func (b *Bwhatsapp) readSession() (whatsapp.Session, error) { + session := whatsapp.Session{} + sessionFile := b.Config.GetString(sessionFile) + + if sessionFile == "" { + return session, errors.New("if you won't set SessionFile then you will need to scan QR code on every restart") } - // try to reload this contact - if _, err := b.wc.Store.Contacts.GetAllContacts(); err != nil { - b.Log.Errorf("error on update of contacts: %v", err) + file, err := os.Open(sessionFile) + if err != nil { + return session, err } - allcontacts, err := b.wc.Store.Contacts.GetAllContacts() + defer file.Close() + + decoder := gob.NewDecoder(file) + + return session, decoder.Decode(&session) +} + +func (b *Bwhatsapp) writeSession(session whatsapp.Session) error { + sessionFile := b.Config.GetString(sessionFile) + + if sessionFile == "" { + // we already sent a warning while starting the bridge, so let's be quiet here + return nil + } + + file, err := os.Create(sessionFile) if err != nil { - b.Log.Errorf("error on update of contacts: %v", err) + return err + } + + defer file.Close() + + encoder := gob.NewEncoder(file) + + return encoder.Encode(session) +} + +func (b *Bwhatsapp) restoreSession() (*whatsapp.Session, error) { + session, err := b.readSession() + if err != nil { + b.Log.Warn(err.Error()) } - if len(allcontacts) > 0 { - b.contacts = allcontacts + b.Log.Debugln("Restoring WhatsApp session..") + + session, err = b.conn.RestoreWithSession(session) + if err != nil { + // restore session connection timed out (I couldn't get over it without logging in again) + return nil, errors.New("failed to restore session: " + err.Error()) } - if sender, exists := b.contacts[senderJid]; exists { - if sender.FullName != "" { - return sender.FullName + b.Log.Debugln("Session restored successfully!") + + return &session, nil +} + +func (b *Bwhatsapp) getSenderName(senderJid string) string { + if sender, exists := b.users[senderJid]; exists { + if sender.Name != "" { + return sender.Name } // if user is not in phone contacts // it is the most obvious scenario unless you sync your phone contacts with some remote updated source // users can change it in their WhatsApp settings -> profile -> click on Avatar - if sender.PushName != "" { - return sender.PushName + if sender.Notify != "" { + return sender.Notify } - if sender.FirstName != "" { - return sender.FirstName + if sender.Short != "" { + return sender.Short } } - return "Someone" + // try to reload this contact + _, err := b.conn.Contacts() + if err != nil { + b.Log.Errorf("error on update of contacts: %v", err) + } + + if contact, exists := b.conn.Store.Contacts[senderJid]; exists { + // Add it to the user map + b.users[senderJid] = contact + + if contact.Name != "" { + return contact.Name + } + // if user is not in phone contacts + // same as above + return contact.Notify + } + + return "" } -func (b *Bwhatsapp) getSenderNotify(senderJid types.JID) string { - if sender, exists := b.contacts[senderJid]; exists { - return sender.PushName +func (b *Bwhatsapp) getSenderNotify(senderJid string) string { + if sender, exists := b.users[senderJid]; exists { + return sender.Notify } return "" } -func (b *Bwhatsapp) GetProfilePicThumb(jid string) (*types.ProfilePictureInfo, error) { - pjid, _ := types.ParseJID(jid) - info, err := b.wc.GetProfilePictureInfo(pjid, true) +func (b *Bwhatsapp) GetProfilePicThumb(jid string) (*ProfilePicInfo, error) { + data, err := b.conn.GetProfilePicThumb(jid) if err != nil { return nil, fmt.Errorf("failed to get avatar: %v", err) } + content := <-data + info := &ProfilePicInfo{} + + err = json.Unmarshal([]byte(content), info) + if err != nil { + return info, fmt.Errorf("failed to unmarshal avatar info: %v", err) + } + return info, nil } @@ -88,19 +161,3 @@ func isGroupJid(identifier string) bool { strings.HasSuffix(identifier, "@temp") || strings.HasSuffix(identifier, "@broadcast") } - -func (b *Bwhatsapp) getDevice() (*store.Device, error) { - device := &store.Device{} - - storeContainer, err := sqlstore.New("sqlite", "file:"+b.Config.GetString("sessionfile")+".db?_foreign_keys=on&_pragma=busy_timeout=10000", nil) - if err != nil { - return device, fmt.Errorf("failed to connect to database: %v", err) - } - - device, err = storeContainer.GetFirstDevice() - if err != nil { - return device, fmt.Errorf("failed to get device: %v", err) - } - - return device, nil -} -- cgit v1.2.3