2018-08-23 00:12:26 +02:00
|
|
|
// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
|
2019-01-12 14:54:04 +01:00
|
|
|
// Copyright (C) 2019 Tulir Asokan
|
2018-08-23 00:12:26 +02:00
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Affero General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
2018-08-26 00:55:21 +02:00
|
|
|
package whatsappExt
|
2018-08-23 00:12:26 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2018-08-26 15:11:48 +02:00
|
|
|
"fmt"
|
2018-08-23 00:12:26 +02:00
|
|
|
"io"
|
2018-08-26 15:11:48 +02:00
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
2018-08-23 00:12:26 +02:00
|
|
|
"strings"
|
2018-08-26 15:11:48 +02:00
|
|
|
|
|
|
|
"github.com/Rhymen/go-whatsapp"
|
2018-08-23 00:12:26 +02:00
|
|
|
)
|
|
|
|
|
2018-08-23 23:51:40 +02:00
|
|
|
const (
|
|
|
|
OldUserSuffix = "@c.us"
|
|
|
|
NewUserSuffix = "@s.whatsapp.net"
|
|
|
|
)
|
|
|
|
|
2018-08-23 00:12:26 +02:00
|
|
|
type ExtendedConn struct {
|
|
|
|
*whatsapp.Conn
|
2018-08-23 23:51:40 +02:00
|
|
|
|
|
|
|
handlers []whatsapp.Handler
|
2018-08-23 00:12:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func ExtendConn(conn *whatsapp.Conn) *ExtendedConn {
|
2018-08-23 23:51:40 +02:00
|
|
|
ext := &ExtendedConn{
|
2018-08-23 00:12:26 +02:00
|
|
|
Conn: conn,
|
|
|
|
}
|
2018-08-23 23:51:40 +02:00
|
|
|
ext.Conn.AddHandler(ext)
|
|
|
|
return ext
|
2018-08-23 00:12:26 +02:00
|
|
|
}
|
|
|
|
|
2019-05-23 19:09:13 +02:00
|
|
|
func (ext *ExtendedConn) AddHandler(handler whatsapp.Handler) {
|
|
|
|
ext.Conn.AddHandler(handler)
|
|
|
|
ext.handlers = append(ext.handlers, handler)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ext *ExtendedConn) RemoveHandler(handler whatsapp.Handler) bool {
|
|
|
|
ext.Conn.RemoveHandler(handler)
|
|
|
|
for i, v := range ext.handlers {
|
|
|
|
if v == handler {
|
|
|
|
ext.handlers = append(ext.handlers[:i], ext.handlers[i+1:]...)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ext *ExtendedConn) RemoveHandlers() {
|
|
|
|
ext.Conn.RemoveHandlers()
|
|
|
|
ext.handlers = make([]whatsapp.Handler, 0)
|
|
|
|
}
|
|
|
|
|
2019-05-21 22:44:14 +02:00
|
|
|
func (ext *ExtendedConn) shouldCallSynchronously(handler whatsapp.Handler) bool {
|
|
|
|
sh, ok := handler.(whatsapp.SyncHandler)
|
|
|
|
return ok && sh.ShouldCallSynchronously()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ext *ExtendedConn) ShouldCallSynchronously() bool {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2018-08-23 00:12:26 +02:00
|
|
|
type GroupInfo struct {
|
|
|
|
JID string `json:"jid"`
|
|
|
|
OwnerJID string `json:"owner"`
|
|
|
|
|
|
|
|
Name string `json:"subject"`
|
|
|
|
NameSetTime int64 `json:"subjectTime"`
|
|
|
|
NameSetBy string `json:"subjectOwner"`
|
|
|
|
|
2020-10-12 12:59:14 +02:00
|
|
|
Announce bool `json:"announce"` // Can only admins send messages?
|
|
|
|
|
2018-08-23 00:12:26 +02:00
|
|
|
Topic string `json:"desc"`
|
|
|
|
TopicID string `json:"descId"`
|
|
|
|
TopicSetAt int64 `json:"descTime"`
|
|
|
|
TopicSetBy string `json:"descOwner"`
|
|
|
|
|
|
|
|
GroupCreated int64 `json:"creation"`
|
|
|
|
|
2018-12-05 09:20:39 +01:00
|
|
|
Status int16 `json:"status"`
|
|
|
|
|
2018-08-23 00:12:26 +02:00
|
|
|
Participants []struct {
|
|
|
|
JID string `json:"id"`
|
|
|
|
IsAdmin bool `json:"isAdmin"`
|
|
|
|
IsSuperAdmin bool `json:"isSuperAdmin"`
|
|
|
|
} `json:"participants"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ext *ExtendedConn) GetGroupMetaData(jid string) (*GroupInfo, error) {
|
|
|
|
data, err := ext.Conn.GetGroupMetaData(jid)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to get group metadata: %v", err)
|
|
|
|
}
|
|
|
|
content := <-data
|
2018-08-23 23:51:40 +02:00
|
|
|
|
2018-08-23 00:12:26 +02:00
|
|
|
info := &GroupInfo{}
|
|
|
|
err = json.Unmarshal([]byte(content), info)
|
|
|
|
if err != nil {
|
|
|
|
return info, fmt.Errorf("failed to unmarshal group metadata: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for index, participant := range info.Participants {
|
2018-08-23 23:51:40 +02:00
|
|
|
info.Participants[index].JID = strings.Replace(participant.JID, OldUserSuffix, NewUserSuffix, 1)
|
2018-08-23 00:12:26 +02:00
|
|
|
}
|
2018-08-26 00:55:21 +02:00
|
|
|
info.NameSetBy = strings.Replace(info.NameSetBy, OldUserSuffix, NewUserSuffix, 1)
|
|
|
|
info.TopicSetBy = strings.Replace(info.TopicSetBy, OldUserSuffix, NewUserSuffix, 1)
|
2018-08-23 00:12:26 +02:00
|
|
|
|
|
|
|
return info, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type ProfilePicInfo struct {
|
|
|
|
URL string `json:"eurl"`
|
|
|
|
Tag string `json:"tag"`
|
2018-12-05 10:30:07 +01:00
|
|
|
|
2020-07-10 14:23:32 +02:00
|
|
|
Status int `json:"status"`
|
2018-08-23 00:12:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ppi *ProfilePicInfo) Download() (io.ReadCloser, error) {
|
|
|
|
resp, err := http.Get(ppi.URL)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp.Body, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ppi *ProfilePicInfo) DownloadBytes() ([]byte, error) {
|
|
|
|
body, err := ppi.Download()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer body.Close()
|
|
|
|
data, err := ioutil.ReadAll(body)
|
|
|
|
return data, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ext *ExtendedConn) GetProfilePicThumb(jid string) (*ProfilePicInfo, error) {
|
|
|
|
data, err := ext.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
|
|
|
|
}
|