Very spammy and buggy prototype.
parent
2a175e4bfc
commit
cd5696954c
@ -0,0 +1,84 @@
|
||||
package botcommands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/Rhymen/go-whatsapp"
|
||||
"github.com/hugot/go-deltachat/deltachat"
|
||||
)
|
||||
|
||||
type Database interface {
|
||||
GetWhappJIDForDCID(DCID uint32) (*string, error)
|
||||
}
|
||||
|
||||
func NewWhappBridge(
|
||||
wac *whatsapp.Conn,
|
||||
db Database,
|
||||
UserChatID uint32,
|
||||
) *WhappBridge {
|
||||
return &WhappBridge{
|
||||
wac: wac,
|
||||
db: db,
|
||||
UserChatID: UserChatID,
|
||||
}
|
||||
}
|
||||
|
||||
type WhappBridge struct {
|
||||
wac *whatsapp.Conn
|
||||
db Database
|
||||
UserChatID uint32
|
||||
}
|
||||
|
||||
func (b *WhappBridge) Accepts(c *deltachat.Chat, m *deltachat.Message) bool {
|
||||
chatID := c.GetID()
|
||||
|
||||
chatJID, err := b.db.GetWhappJIDForDCID(chatID)
|
||||
|
||||
if err != nil {
|
||||
// The database is failing, time to die :(
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return chatJID != nil
|
||||
}
|
||||
|
||||
func (b *WhappBridge) Execute(
|
||||
c *deltachat.Context,
|
||||
chat *deltachat.Chat,
|
||||
m *deltachat.Message,
|
||||
) {
|
||||
JID, err := b.db.GetWhappJIDForDCID(chat.GetID())
|
||||
|
||||
if err != nil {
|
||||
c.SendTextMessage(
|
||||
b.UserChatID,
|
||||
fmt.Sprintf(
|
||||
"Whapp bridge dying: %s",
|
||||
err.Error(),
|
||||
),
|
||||
)
|
||||
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
text := whatsapp.TextMessage{
|
||||
Info: whatsapp.MessageInfo{
|
||||
RemoteJid: *JID,
|
||||
},
|
||||
Text: m.GetText(),
|
||||
}
|
||||
|
||||
_, err = b.wac.Send(text)
|
||||
|
||||
if err != nil {
|
||||
c.SendTextMessage(
|
||||
b.UserChatID,
|
||||
fmt.Sprintf(
|
||||
"Error sending message to %s. Message contents: %s",
|
||||
JID,
|
||||
m.GetText(),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
db *bbolt.DB
|
||||
dbPath string
|
||||
}
|
||||
|
||||
const (
|
||||
JID_TO_DCID_INT uint8 = iota
|
||||
DCID_TO_JID_INT
|
||||
KEY_VALUE_INT
|
||||
)
|
||||
|
||||
var (
|
||||
JID_TO_DCID = []byte{JID_TO_DCID_INT}
|
||||
DCID_TO_JID = []byte{DCID_TO_JID_INT}
|
||||
KEY_VALUE = []byte{KEY_VALUE_INT}
|
||||
)
|
||||
|
||||
func (d *Database) Init() error {
|
||||
db, err := bbolt.Open(d.dbPath, 0600, nil)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.Update(func(tx *bbolt.Tx) error {
|
||||
_, err = tx.CreateBucketIfNotExists(JID_TO_DCID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.CreateBucketIfNotExists(DCID_TO_JID)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.CreateBucketIfNotExists(KEY_VALUE)
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
d.db = db
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Database) GetDCIDForWhappJID(JID string) (*uint32, error) {
|
||||
var DCID *uint32
|
||||
|
||||
err := d.db.View(func(tx *bbolt.Tx) error {
|
||||
rawDCID := tx.Bucket(JID_TO_DCID).Get([]byte(JID))
|
||||
|
||||
if rawDCID == nil {
|
||||
DCID = nil
|
||||
} else {
|
||||
i := binary.LittleEndian.Uint32(rawDCID)
|
||||
DCID = &i
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return DCID, err
|
||||
}
|
||||
|
||||
func (d *Database) GetWhappJIDForDCID(DCID uint32) (*string, error) {
|
||||
var JID *string
|
||||
|
||||
rawDCID := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(rawDCID, DCID)
|
||||
|
||||
err := d.db.View(func(tx *bbolt.Tx) error {
|
||||
|
||||
rawJID := tx.Bucket(DCID_TO_JID).Get(rawDCID)
|
||||
|
||||
if rawJID == nil {
|
||||
JID = nil
|
||||
} else {
|
||||
str := string(rawJID)
|
||||
JID = &str
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return JID, err
|
||||
}
|
||||
|
||||
func (d *Database) StoreDCIDForJID(JID string, DCID uint32) error {
|
||||
err := d.db.Update(func(tx *bbolt.Tx) error {
|
||||
|
||||
DCIDbs := make([]byte, 4)
|
||||
|
||||
binary.LittleEndian.PutUint32(DCIDbs, DCID)
|
||||
|
||||
err := tx.Bucket(JID_TO_DCID).Put([]byte(JID), DCIDbs)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Bucket(DCID_TO_JID).Put(DCIDbs, []byte(JID))
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Database) Put(key []byte, value []byte) error {
|
||||
err := d.db.Update(func(tx *bbolt.Tx) error {
|
||||
err := tx.Bucket(KEY_VALUE).Put(key, value)
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Database) Get(key []byte) []byte {
|
||||
var value []byte
|
||||
|
||||
d.db.View(func(tx *bbolt.Tx) error {
|
||||
value = tx.Bucket(KEY_VALUE).Get(key)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return value
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/Rhymen/go-whatsapp"
|
||||
"github.com/hugot/go-deltachat/deltachat"
|
||||
)
|
||||
|
||||
type WhappHandler struct {
|
||||
dcContext *deltachat.Context
|
||||
db *Database
|
||||
dcUserID uint32
|
||||
wac *whatsapp.Conn
|
||||
}
|
||||
|
||||
// Find or create a deltachat verified group chat for a whatsapp JID and return it's ID.
|
||||
func (h *WhappHandler) getOrCreateDCIDForJID(JID string, isGroup bool) (uint32, error) {
|
||||
if DCID, _ := h.db.GetDCIDForWhappJID(JID); DCID != nil {
|
||||
return *DCID, nil
|
||||
}
|
||||
|
||||
chatName := JID
|
||||
if isGroup {
|
||||
chat, ok := h.wac.Store.Chats[JID]
|
||||
|
||||
if ok {
|
||||
chatName = chat.Name
|
||||
}
|
||||
} else {
|
||||
contact, ok := h.wac.Store.Contacts[JID]
|
||||
|
||||
if ok {
|
||||
chatName = contact.Name
|
||||
}
|
||||
}
|
||||
|
||||
DCID := h.dcContext.CreateGroupChat(true, chatName)
|
||||
|
||||
err := h.db.StoreDCIDForJID(JID, DCID)
|
||||
|
||||
if err != nil {
|
||||
return DCID, err
|
||||
}
|
||||
|
||||
h.dcContext.AddContactToChat(DCID, h.dcUserID)
|
||||
|
||||
return DCID, err
|
||||
}
|
||||
|
||||
func (h *WhappHandler) HandleError(err error) {
|
||||
log.Println("Whatsapp Error: " + err.Error())
|
||||
}
|
||||
|
||||
func (h *WhappHandler) HandleTextMessage(m whatsapp.TextMessage) {
|
||||
JID := m.Info.RemoteJid
|
||||
|
||||
DCID, err := h.getOrCreateDCIDForJID(JID, m.Info.RemoteJid != m.Info.SenderJid)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
||||
chatID := h.dcContext.GetChatIDByContactID(h.dcUserID)
|
||||
h.dcContext.SendTextMessage(
|
||||
chatID,
|
||||
err.Error(),
|
||||
)
|
||||
}
|
||||
|
||||
senderName := m.Info.SenderJid
|
||||
contact, ok := h.wac.Store.Contacts[m.Info.SenderJid]
|
||||
if ok {
|
||||
senderName = contact.Name
|
||||
}
|
||||
|
||||
h.dcContext.SendTextMessage(
|
||||
DCID,
|
||||
fmt.Sprintf("%s:\n%s", senderName, m.Text),
|
||||
)
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"mime"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/Rhymen/go-whatsapp"
|
||||
"github.com/hugot/go-deltachat/deltachat"
|
||||
"github.com/skip2/go-qrcode"
|
||||
)
|
||||
|
||||
func CreateAndLoginWhappConnection(
|
||||
storageDir string,
|
||||
dcContext *deltachat.Context,
|
||||
dcUserID uint32,
|
||||
) (*whatsapp.Conn, error) {
|
||||
wac, err := whatsapp.NewConn(20 * time.Second)
|
||||
|
||||
if err != nil {
|
||||
return wac, err
|
||||
}
|
||||
|
||||
var session whatsapp.Session
|
||||
|
||||
sessionFile := storageDir + "/whapp-session.json"
|
||||
if _, err := os.Stat(sessionFile); os.IsNotExist(err) {
|
||||
session, err = WhappQrLogin(storageDir, wac, dcContext, dcUserID)
|
||||
|
||||
if err != nil {
|
||||
return wac, err
|
||||
}
|
||||
} else {
|
||||
session = whatsapp.Session{}
|
||||
|
||||
sessionJson, err := ioutil.ReadFile(sessionFile)
|
||||
|
||||
err = json.Unmarshal(sessionJson, &session)
|
||||
|
||||
if err != nil {
|
||||
return wac, err
|
||||
}
|
||||
|
||||
session, err = wac.RestoreWithSession(session)
|
||||
|
||||
if err != nil {
|
||||
return wac, err
|
||||
}
|
||||
}
|
||||
|
||||
err = StoreWhappSession(session, storageDir)
|
||||
|
||||
return wac, err
|
||||
}
|
||||
|
||||
func WhappQrLogin(
|
||||
storageDir string,
|
||||
wac *whatsapp.Conn,
|
||||
dcContext *deltachat.Context,
|
||||
dcUserID uint32,
|
||||
) (whatsapp.Session, error) {
|
||||
qrChan := make(chan string)
|
||||
|
||||
go func() {
|
||||
qrCode := <-qrChan
|
||||
|
||||
tmpFile, err := ioutil.TempFile(storageDir+"/tmp", "qr")
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = qrcode.WriteFile(qrCode, qrcode.Medium, 256, tmpFile.Name())
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
message := dcContext.NewMessage(deltachat.DC_MSG_IMAGE)
|
||||
|
||||
log.Println("MIME: " + mime.TypeByExtension("png"))
|
||||
|
||||
message.SetFile(tmpFile.Name(), "image/png")
|
||||
|
||||
message.SetText("Scan this QR code from whatsapp")
|
||||
|
||||
dcContext.SendMessage(
|
||||
dcContext.GetChatIDByContactID(dcUserID),
|
||||
message,
|
||||
)
|
||||
}()
|
||||
|
||||
session, err := wac.Login(qrChan)
|
||||
|
||||
return session, err
|
||||
}
|
||||
|
||||
func StoreWhappSession(session whatsapp.Session, storageDir string) error {
|
||||
sessionJson, err := json.Marshal(session)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(storageDir+"/whapp-session.json", sessionJson, 0600)
|
||||
|
||||
return err
|
||||
}
|
Loading…
Reference in New Issue