Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04960123da | ||
|
|
ab03aeb7a0 | ||
|
|
f6860b56b8 | ||
|
|
6bea425367 | ||
|
|
1b3379b613 |
@@ -38,11 +38,11 @@ Always fresh, always up to date.
|
|||||||
- Download a release
|
- Download a release
|
||||||
- Put the binary in your PATH (optional)
|
- Put the binary in your PATH (optional)
|
||||||
- Run with `whatscli` (or double-click)
|
- Run with `whatscli` (or double-click)
|
||||||
- Scan the QR code with WhatsApp on your phone (maybe resize shell)
|
- Scan the QR code with WhatsApp on your phone (resize shell or change font size to see whole code)
|
||||||
|
|
||||||
### Package Managers
|
### Package Managers
|
||||||
|
|
||||||
Some unofficial ways to install via package managers are supported but the installed version might be out of date.
|
Some ways to install via package managers are supported but the installed version might be out of date.
|
||||||
|
|
||||||
#### MacOS (homebrew)
|
#### MacOS (homebrew)
|
||||||
|
|
||||||
|
|||||||
4
main.go
4
main.go
@@ -19,7 +19,7 @@ type waMsg struct {
|
|||||||
Text string
|
Text string
|
||||||
}
|
}
|
||||||
|
|
||||||
var VERSION string = "v0.6.8"
|
var VERSION string = "v0.6.10"
|
||||||
|
|
||||||
var sendChannel chan waMsg
|
var sendChannel chan waMsg
|
||||||
var textChannel chan whatsapp.TextMessage
|
var textChannel chan whatsapp.TextMessage
|
||||||
@@ -552,7 +552,7 @@ type textHandler struct{}
|
|||||||
|
|
||||||
// HandleError implements the error handler interface for go-whatsapp
|
// HandleError implements the error handler interface for go-whatsapp
|
||||||
func (t textHandler) HandleError(err error) {
|
func (t textHandler) HandleError(err error) {
|
||||||
// TODO : handle go routine here
|
PrintText("[red]go-whatsapp reported an error:[-]")
|
||||||
PrintError(err)
|
PrintError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,18 @@ package messages
|
|||||||
import (
|
import (
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/rivo/tview"
|
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/rivo/tview"
|
||||||
|
|
||||||
"github.com/Rhymen/go-whatsapp"
|
"github.com/Rhymen/go-whatsapp"
|
||||||
"github.com/normen/whatscli/qrcode"
|
"github.com/normen/whatscli/qrcode"
|
||||||
)
|
)
|
||||||
|
|
||||||
var textView *tview.TextView
|
var textView *tview.TextView
|
||||||
|
var connMutex sync.Mutex
|
||||||
|
|
||||||
// TODO: remove this circular dependeny in favor of a better way
|
// TODO: remove this circular dependeny in favor of a better way
|
||||||
func SetTextView(tv *tview.TextView) {
|
func SetTextView(tv *tview.TextView) {
|
||||||
@@ -20,6 +23,8 @@ func SetTextView(tv *tview.TextView) {
|
|||||||
|
|
||||||
// gets an existing connection or creates one
|
// gets an existing connection or creates one
|
||||||
func GetConnection() *whatsapp.Conn {
|
func GetConnection() *whatsapp.Conn {
|
||||||
|
connMutex.Lock()
|
||||||
|
defer connMutex.Unlock()
|
||||||
var wac *whatsapp.Conn
|
var wac *whatsapp.Conn
|
||||||
if connection == nil {
|
if connection == nil {
|
||||||
wacc, err := whatsapp.NewConn(5 * time.Second)
|
wacc, err := whatsapp.NewConn(5 * time.Second)
|
||||||
@@ -44,8 +49,10 @@ func Login() error {
|
|||||||
// LoginWithConnection logs in the user using a provided connection. It ries to see if a session already exists. If not, tries to create a
|
// LoginWithConnection logs in the user using a provided connection. It ries to see if a session already exists. If not, tries to create a
|
||||||
// new one using qr scanned on the terminal.
|
// new one using qr scanned on the terminal.
|
||||||
func LoginWithConnection(wac *whatsapp.Conn) error {
|
func LoginWithConnection(wac *whatsapp.Conn) error {
|
||||||
if connection != nil && connection.GetConnected() {
|
connMutex.Lock()
|
||||||
connection.Disconnect()
|
defer connMutex.Unlock()
|
||||||
|
if wac != nil && wac.GetConnected() {
|
||||||
|
wac.Disconnect()
|
||||||
}
|
}
|
||||||
//load saved session
|
//load saved session
|
||||||
session, err := readSession()
|
session, err := readSession()
|
||||||
@@ -80,6 +87,8 @@ func LoginWithConnection(wac *whatsapp.Conn) error {
|
|||||||
|
|
||||||
// Logout logs out the user.
|
// Logout logs out the user.
|
||||||
func Logout() error {
|
func Logout() error {
|
||||||
|
connMutex.Lock()
|
||||||
|
defer connMutex.Unlock()
|
||||||
return removeSession()
|
return removeSession()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Rhymen/go-whatsapp"
|
"github.com/Rhymen/go-whatsapp"
|
||||||
@@ -21,41 +22,46 @@ type MessageDatabase struct {
|
|||||||
messagesById map[string]*whatsapp.TextMessage // text messages stored by message ID
|
messagesById map[string]*whatsapp.TextMessage // text messages stored by message ID
|
||||||
latestMessage map[string]uint64 // last message from RemoteJid
|
latestMessage map[string]uint64 // last message from RemoteJid
|
||||||
otherMessages map[string]*interface{} // other non-text messages, stored by ID
|
otherMessages map[string]*interface{} // other non-text messages, stored by ID
|
||||||
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize the database
|
// initialize the database
|
||||||
func (db *MessageDatabase) Init() {
|
func (db *MessageDatabase) Init() {
|
||||||
//var this = *db
|
//var this = *db
|
||||||
(*db).textMessages = make(map[string][]*whatsapp.TextMessage)
|
db.textMessages = make(map[string][]*whatsapp.TextMessage)
|
||||||
(*db).messagesById = make(map[string]*whatsapp.TextMessage)
|
db.messagesById = make(map[string]*whatsapp.TextMessage)
|
||||||
(*db).otherMessages = make(map[string]*interface{})
|
db.otherMessages = make(map[string]*interface{})
|
||||||
(*db).latestMessage = make(map[string]uint64)
|
db.latestMessage = make(map[string]uint64)
|
||||||
}
|
}
|
||||||
|
|
||||||
// add a text message to the database, stored by RemoteJid
|
// add a text message to the database, stored by RemoteJid
|
||||||
func (db *MessageDatabase) AddTextMessage(msg *whatsapp.TextMessage) bool {
|
func (db *MessageDatabase) AddTextMessage(msg *whatsapp.TextMessage) bool {
|
||||||
|
db.mutex.Lock()
|
||||||
|
defer db.mutex.Unlock()
|
||||||
//var this = *db
|
//var this = *db
|
||||||
var didNew = false
|
var didNew = false
|
||||||
var wid = msg.Info.RemoteJid
|
var wid = msg.Info.RemoteJid
|
||||||
if (*db).textMessages[wid] == nil {
|
if db.textMessages[wid] == nil {
|
||||||
var newArr = []*whatsapp.TextMessage{}
|
var newArr = []*whatsapp.TextMessage{}
|
||||||
(*db).textMessages[wid] = newArr
|
db.textMessages[wid] = newArr
|
||||||
(*db).latestMessage[wid] = msg.Info.Timestamp
|
db.latestMessage[wid] = msg.Info.Timestamp
|
||||||
didNew = true
|
didNew = true
|
||||||
} else if (*db).latestMessage[wid] < msg.Info.Timestamp {
|
} else if db.latestMessage[wid] < msg.Info.Timestamp {
|
||||||
(*db).latestMessage[wid] = msg.Info.Timestamp
|
db.latestMessage[wid] = msg.Info.Timestamp
|
||||||
didNew = true
|
didNew = true
|
||||||
}
|
}
|
||||||
(*db).textMessages[wid] = append((*db).textMessages[wid], msg)
|
db.textMessages[wid] = append(db.textMessages[wid], msg)
|
||||||
(*db).messagesById[msg.Info.Id] = msg
|
db.messagesById[msg.Info.Id] = msg
|
||||||
sort.Slice((*db).textMessages[wid], func(i, j int) bool {
|
sort.Slice(db.textMessages[wid], func(i, j int) bool {
|
||||||
return (*db).textMessages[wid][i].Info.Timestamp < (*db).textMessages[wid][j].Info.Timestamp
|
return db.textMessages[wid][i].Info.Timestamp < db.textMessages[wid][j].Info.Timestamp
|
||||||
})
|
})
|
||||||
return didNew
|
return didNew
|
||||||
}
|
}
|
||||||
|
|
||||||
// add audio/video/image/doc message, stored by message id
|
// add audio/video/image/doc message, stored by message id
|
||||||
func (db *MessageDatabase) AddOtherMessage(msg *interface{}) {
|
func (db *MessageDatabase) AddOtherMessage(msg *interface{}) {
|
||||||
|
db.mutex.Lock()
|
||||||
|
defer db.mutex.Unlock()
|
||||||
var id = ""
|
var id = ""
|
||||||
switch v := (*msg).(type) {
|
switch v := (*msg).(type) {
|
||||||
default:
|
default:
|
||||||
@@ -69,31 +75,35 @@ func (db *MessageDatabase) AddOtherMessage(msg *interface{}) {
|
|||||||
id = v.Info.Id
|
id = v.Info.Id
|
||||||
}
|
}
|
||||||
if id != "" {
|
if id != "" {
|
||||||
(*db).otherMessages[id] = msg
|
db.otherMessages[id] = msg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get an array of all chat ids
|
// get an array of all chat ids
|
||||||
func (db *MessageDatabase) GetContactIds() []string {
|
func (db *MessageDatabase) GetContactIds() []string {
|
||||||
|
db.mutex.Lock()
|
||||||
|
defer db.mutex.Unlock()
|
||||||
//var this = *db
|
//var this = *db
|
||||||
keys := make([]string, len((*db).textMessages))
|
keys := make([]string, len(db.textMessages))
|
||||||
i := 0
|
i := 0
|
||||||
for k := range (*db).textMessages {
|
for k := range db.textMessages {
|
||||||
keys[i] = k
|
keys[i] = k
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
sort.Slice(keys, func(i, j int) bool {
|
sort.Slice(keys, func(i, j int) bool {
|
||||||
return (*db).latestMessage[keys[i]] > (*db).latestMessage[keys[j]]
|
return db.latestMessage[keys[i]] > db.latestMessage[keys[j]]
|
||||||
})
|
})
|
||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *MessageDatabase) GetMessageInfo(id string) string {
|
func (db *MessageDatabase) GetMessageInfo(id string) string {
|
||||||
if _, ok := (*db).otherMessages[id]; ok {
|
db.mutex.Lock()
|
||||||
|
defer db.mutex.Unlock()
|
||||||
|
if _, ok := db.otherMessages[id]; ok {
|
||||||
return "[yellow]OtherMessage[-]"
|
return "[yellow]OtherMessage[-]"
|
||||||
}
|
}
|
||||||
out := ""
|
out := ""
|
||||||
if msg, ok := (*db).messagesById[id]; ok {
|
if msg, ok := db.messagesById[id]; ok {
|
||||||
out += "[yellow]ID: " + msg.Info.Id + "[-]\n"
|
out += "[yellow]ID: " + msg.Info.Id + "[-]\n"
|
||||||
out += "[yellow]PushName: " + msg.Info.PushName + "[-]\n"
|
out += "[yellow]PushName: " + msg.Info.PushName + "[-]\n"
|
||||||
out += "[yellow]RemoteJid: " + msg.Info.RemoteJid + "[-]\n"
|
out += "[yellow]RemoteJid: " + msg.Info.RemoteJid + "[-]\n"
|
||||||
@@ -106,10 +116,12 @@ func (db *MessageDatabase) GetMessageInfo(id string) string {
|
|||||||
|
|
||||||
// get a string containing all messages for a chat by chat id
|
// get a string containing all messages for a chat by chat id
|
||||||
func (db *MessageDatabase) GetMessagesString(wid string) (string, []string) {
|
func (db *MessageDatabase) GetMessagesString(wid string) (string, []string) {
|
||||||
|
db.mutex.Lock()
|
||||||
|
defer db.mutex.Unlock()
|
||||||
//var this = *db
|
//var this = *db
|
||||||
var out = ""
|
var out = ""
|
||||||
var arr = []string{}
|
var arr = []string{}
|
||||||
for _, element := range (*db).textMessages[wid] {
|
for _, element := range db.textMessages[wid] {
|
||||||
out += GetTextMessageString(element)
|
out += GetTextMessageString(element)
|
||||||
out += "\n"
|
out += "\n"
|
||||||
arr = append(arr, element.Info.Id)
|
arr = append(arr, element.Info.Id)
|
||||||
@@ -117,29 +129,11 @@ func (db *MessageDatabase) GetMessagesString(wid string) (string, []string) {
|
|||||||
return out, arr
|
return out, arr
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a formatted string with regions based on message ID from a text message
|
|
||||||
func GetTextMessageString(msg *whatsapp.TextMessage) string {
|
|
||||||
out := ""
|
|
||||||
text := tview.Escape((*msg).Text)
|
|
||||||
tim := time.Unix(int64((*msg).Info.Timestamp), 0)
|
|
||||||
out += "[\""
|
|
||||||
out += (*msg).Info.Id
|
|
||||||
out += "\"]"
|
|
||||||
if (*msg).Info.FromMe { //msg from me
|
|
||||||
out += "[-::d](" + tim.Format("02-01-06 15:04:05") + ") [blue::b]Me: [-::-]" + text
|
|
||||||
} else if strings.Contains((*msg).Info.RemoteJid, GROUPSUFFIX) { // group msg
|
|
||||||
userId := (*msg).Info.SenderJid
|
|
||||||
out += "[-::d](" + tim.Format("02-01-06 15:04:05") + ") [green::b]" + GetIdShort(userId) + ": [-::-]" + text
|
|
||||||
} else { // message from others
|
|
||||||
out += "[-::d](" + tim.Format("02-01-06 15:04:05") + ") [green::b]" + GetIdShort((*msg).Info.RemoteJid) + ": [-::-]" + text
|
|
||||||
}
|
|
||||||
out += "[\"\"]"
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// load data for message specified by message id TODO: support types
|
// load data for message specified by message id TODO: support types
|
||||||
func (db *MessageDatabase) LoadMessageData(wid string) ([]byte, error) {
|
func (db *MessageDatabase) LoadMessageData(wid string) ([]byte, error) {
|
||||||
if msg, ok := (*db).otherMessages[wid]; ok {
|
db.mutex.Lock()
|
||||||
|
defer db.mutex.Unlock()
|
||||||
|
if msg, ok := db.otherMessages[wid]; ok {
|
||||||
switch v := (*msg).(type) {
|
switch v := (*msg).(type) {
|
||||||
default:
|
default:
|
||||||
case whatsapp.ImageMessage:
|
case whatsapp.ImageMessage:
|
||||||
@@ -157,7 +151,9 @@ func (db *MessageDatabase) LoadMessageData(wid string) ([]byte, error) {
|
|||||||
|
|
||||||
// attempts to download a messages attachments, returns path or error message
|
// attempts to download a messages attachments, returns path or error message
|
||||||
func (db *MessageDatabase) DownloadMessage(wid string, open bool) (string, error) {
|
func (db *MessageDatabase) DownloadMessage(wid string, open bool) (string, error) {
|
||||||
if msg, ok := (*db).otherMessages[wid]; ok {
|
db.mutex.Lock()
|
||||||
|
defer db.mutex.Unlock()
|
||||||
|
if msg, ok := db.otherMessages[wid]; ok {
|
||||||
var fileName string = GetHomeDir() + "Downloads" + string(os.PathSeparator)
|
var fileName string = GetHomeDir() + "Downloads" + string(os.PathSeparator)
|
||||||
switch v := (*msg).(type) {
|
switch v := (*msg).(type) {
|
||||||
default:
|
default:
|
||||||
@@ -210,6 +206,26 @@ func (db *MessageDatabase) DownloadMessage(wid string, open bool) (string, error
|
|||||||
return "", errors.New("No attachments found")
|
return "", errors.New("No attachments found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create a formatted string with regions based on message ID from a text message
|
||||||
|
func GetTextMessageString(msg *whatsapp.TextMessage) string {
|
||||||
|
out := ""
|
||||||
|
text := tview.Escape(msg.Text)
|
||||||
|
tim := time.Unix(int64(msg.Info.Timestamp), 0)
|
||||||
|
out += "[\""
|
||||||
|
out += msg.Info.Id
|
||||||
|
out += "\"]"
|
||||||
|
if msg.Info.FromMe { //msg from me
|
||||||
|
out += "[-::d](" + tim.Format("02-01-06 15:04:05") + ") [blue::b]Me: [-::-]" + text
|
||||||
|
} else if strings.Contains(msg.Info.RemoteJid, GROUPSUFFIX) { // group msg
|
||||||
|
userId := msg.Info.SenderJid
|
||||||
|
out += "[-::d](" + tim.Format("02-01-06 15:04:05") + ") [green::b]" + GetIdShort(userId) + ": [-::-]" + text
|
||||||
|
} else { // message from others
|
||||||
|
out += "[-::d](" + tim.Format("02-01-06 15:04:05") + ") [green::b]" + GetIdShort(msg.Info.RemoteJid) + ": [-::-]" + text
|
||||||
|
}
|
||||||
|
out += "[\"\"]"
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// helper to save an attachment and open it if specified
|
// helper to save an attachment and open it if specified
|
||||||
func saveAttachment(data []byte, path string, openIt bool) (string, error) {
|
func saveAttachment(data []byte, path string, openIt bool) (string, error) {
|
||||||
err := ioutil.WriteFile(path, data, 0644)
|
err := ioutil.WriteFile(path, data, 0644)
|
||||||
|
|||||||
Reference in New Issue
Block a user