Remove irrelevant code

This commit is contained in:
zhaoYangguang 2020-11-27 12:17:47 +08:00
parent 5bf0838329
commit b2471e801f
18 changed files with 224 additions and 1487 deletions

View File

@ -8,11 +8,9 @@ import (
"math"
"time"
//"math"
"sort"
"strconv"
"strings"
//"time"
"maunium.net/go/maulogger/v2"
@ -21,8 +19,6 @@ import (
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/format"
"maunium.net/go/mautrix/id"
"github.com/kelaresg/matrix-skype/whatsapp-ext"
)
type CommandHandler struct {
@ -697,7 +693,7 @@ func (handler *CommandHandler) CommandOpen(ce *CommandEvent) {
jid := ce.Args[0]
if strings.HasSuffix(jid, skypeExt.NewUserSuffix) {
ce.Reply("That looks like a user ID. Did you mean `pm %s`?", jid[:len(jid)-len(whatsappExt.NewUserSuffix)])
ce.Reply("That looks like a user ID. Did you mean `pm %s`?", jid[:len(jid)-len(skypeExt.NewUserSuffix)])
return
}
ce.User.Conn.GetConversations("", handler.bridge.Config.Bridge.InitialChatSync)
@ -977,7 +973,7 @@ func (handler *CommandHandler) CommandKick(ce *CommandEvent) {
// reason = ce.Args[0]
//}
if strings.HasSuffix(converationId, whatsappExt.NewUserSuffix) {
if strings.HasSuffix(converationId, skypeExt.NewUserSuffix) {
ce.Reply("**Usage:** `kick <group ID> <contact id>,... reason`")
return
}
@ -995,8 +991,8 @@ func (handler *CommandHandler) CommandKick(ce *CommandEvent) {
portal := user.bridge.GetPortalByJID(database.GroupPortalKey(converationId))
for i, number := range userNumbers {
userNumbers[i] = number // + whatsappExt.NewUserSuffix
member := portal.bridge.GetPuppetByJID(number + whatsappExt.NewUserSuffix)
userNumbers[i] = number // + skypeExt.NewUserSuffix
member := portal.bridge.GetPuppetByJID(number + skypeExt.NewUserSuffix)
if member == nil {
portal.log.Errorln("%s is not a puppet", number)
@ -1025,7 +1021,7 @@ func (handler *CommandHandler) CommandLeave(ce *CommandEvent) {
user := ce.User
groupId := ce.Args[0]
if strings.HasSuffix(groupId, whatsappExt.NewUserSuffix) {
if strings.HasSuffix(groupId, skypeExt.NewUserSuffix) {
ce.Reply("**Usage:** `leave <group JID>`")
return
}

3
go.mod
View File

@ -3,7 +3,6 @@ module github.com/kelaresg/matrix-skype
go 1.14
require (
github.com/Rhymen/go-whatsapp v0.1.0
github.com/chai2010/webp v1.1.0
github.com/gorilla/websocket v1.4.2
github.com/kelaresg/go-skypeapi v0.1.2-0.20201126103218-226d1ec92858
@ -19,6 +18,4 @@ require (
maunium.net/go/mautrix v0.8.0-rc.4
)
replace github.com/Rhymen/go-whatsapp => github.com/tulir/go-whatsapp v0.2.8
replace maunium.net/go/mautrix => github.com/pidongqianqian/mautrix-go v0.8.0-rc.4.0.20201126070406-7b13ac473bcc

379
portal.go
View File

@ -2,13 +2,16 @@ package main
import (
"bytes"
"encoding/gob"
//whatsappExt "github.com/kelaresg/matrix-skype/whatsapp-ext"
//"encoding/gob"
"encoding/hex"
"encoding/json"
"encoding/xml"
"fmt"
skype "github.com/kelaresg/go-skypeapi"
skypeExt "github.com/kelaresg/matrix-skype/skype-ext"
//whatsappExt "github.com/kelaresg/matrix-skype/whatsapp-ext"
"html"
"image"
"image/gif"
@ -28,8 +31,8 @@ import (
"maunium.net/go/mautrix/crypto/attachment"
"github.com/Rhymen/go-whatsapp"
waProto "github.com/Rhymen/go-whatsapp/binary/proto"
//"github.com/Rhymen/go-whatsapp"
//waProto "github.com/Rhymen/go-whatsapp/binary/proto"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/appservice"
@ -40,7 +43,7 @@ import (
"github.com/kelaresg/matrix-skype/database"
"github.com/kelaresg/matrix-skype/types"
"github.com/kelaresg/matrix-skype/whatsapp-ext"
//"github.com/kelaresg/matrix-skype/whatsapp-ext"
)
func (bridge *Bridge) GetPortalByMXID(mxid id.RoomID) *Portal {
@ -251,36 +254,36 @@ func (portal *Portal) isDuplicate(clientMessageId types.SkypeMessageID, id strin
return false
}
func init() {
gob.Register(&waProto.Message{})
}
//func init() {
// gob.Register(&waProto.Message{})
//}
func (portal *Portal) markHandled(source *User, message *waProto.WebMessageInfo, mxid id.EventID) {
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.Content = &skype.Resource{}
msg.Insert()
portal.recentlyHandledLock.Lock()
index := portal.recentlyHandledIndex
portal.recentlyHandledIndex = (portal.recentlyHandledIndex + 1) % recentlyHandledLength
portal.recentlyHandledLock.Unlock()
portal.recentlyHandled[index] = msg.JID
}
//func (portal *Portal) markHandled(source *User, message *waProto.WebMessageInfo, mxid id.EventID) {
// 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.Content = &skype.Resource{}
// msg.Insert()
//
// portal.recentlyHandledLock.Lock()
// index := portal.recentlyHandledIndex
// portal.recentlyHandledIndex = (portal.recentlyHandledIndex + 1) % recentlyHandledLength
// portal.recentlyHandledLock.Unlock()
// portal.recentlyHandled[index] = msg.JID
//}
func (portal *Portal) markHandledSkype(source *User, message *skype.Resource, mxid id.EventID) {
msg := portal.bridge.DB.Message.New()
@ -312,20 +315,20 @@ fmt.Println("markHandledSkype2", msg.JID)
portal.recentlyHandled[index] = msg.JID
}
func (portal *Portal) getMessageIntent(user *User, info whatsapp.MessageInfo) *appservice.IntentAPI {
if info.FromMe {
return portal.bridge.GetPuppetByJID(user.JID).IntentFor(portal)
} else if portal.IsPrivateChat() {
return portal.MainIntent()
} else if len(info.SenderJid) == 0 {
if len(info.Source.GetParticipant()) != 0 {
info.SenderJid = info.Source.GetParticipant()
} else {
return nil
}
}
return portal.bridge.GetPuppetByJID(info.SenderJid).IntentFor(portal)
}
//func (portal *Portal) getMessageIntent(user *User, info whatsapp.MessageInfo) *appservice.IntentAPI {
// if info.FromMe {
// return portal.bridge.GetPuppetByJID(user.JID).IntentFor(portal)
// } else if portal.IsPrivateChat() {
// return portal.MainIntent()
// } else if len(info.SenderJid) == 0 {
// if len(info.Source.GetParticipant()) != 0 {
// info.SenderJid = info.Source.GetParticipant()
// } else {
// return nil
// }
// }
// return portal.bridge.GetPuppetByJID(info.SenderJid).IntentFor(portal)
//}
func (portal *Portal) getMessageIntentSkype(user *User, info skype.Resource) *appservice.IntentAPI {
if info.GetFromMe(user.Conn.Conn) {
@ -385,11 +388,11 @@ func (portal *Portal) startHandlingSkype(source *User, info skype.Resource) (*ap
return nil, nil
}
func (portal *Portal) finishHandling(source *User, message *waProto.WebMessageInfo, mxid id.EventID) {
portal.markHandled(source, message, mxid)
portal.sendDeliveryReceipt(mxid)
portal.log.Debugln("Handled message", message.GetKey().GetId(), "->", mxid)
}
//func (portal *Portal) finishHandling(source *User, message *waProto.WebMessageInfo, mxid id.EventID) {
// portal.markHandled(source, message, mxid)
// portal.sendDeliveryReceipt(mxid)
// portal.log.Debugln("Handled message", message.GetKey().GetId(), "->", mxid)
//}
func (portal *Portal) finishHandlingSkype(source *User, message *skype.Resource, mxid id.EventID) {
portal.markHandledSkype(source, message, mxid)
@ -1291,21 +1294,21 @@ func (portal *Portal) MainIntent() *appservice.IntentAPI {
return portal.bridge.Bot
}
func (portal *Portal) SetReply(content *event.MessageEventContent, info whatsapp.ContextInfo) {
if len(info.QuotedMessageID) == 0 {
return
}
message := portal.bridge.DB.Message.GetByJID(portal.Key, info.QuotedMessageID)
if message != nil {
evt, err := portal.MainIntent().GetEvent(portal.MXID, message.MXID)
if err != nil {
portal.log.Warnln("Failed to get reply target:", err)
return
}
content.SetReply(evt)
}
return
}
//func (portal *Portal) SetReply(content *event.MessageEventContent, info whatsapp.ContextInfo) {
// if len(info.QuotedMessageID) == 0 {
// return
// }
// message := portal.bridge.DB.Message.GetByJID(portal.Key, info.QuotedMessageID)
// if message != nil {
// evt, err := portal.MainIntent().GetEvent(portal.MXID, message.MXID)
// if err != nil {
// portal.log.Warnln("Failed to get reply target:", err)
// return
// }
// content.SetReply(evt)
// }
// return
//}
func (portal *Portal) SetReplySkype(content *event.MessageEventContent, info skype.Resource) {
if len(info.Id) == 0 {
@ -1347,32 +1350,31 @@ func (portal *Portal) HandleMessageRevokeSkype(user *User, message skype.Resourc
msg.Delete()
}
func (portal *Portal) HandleMessageRevoke(user *User, message whatsappExt.MessageRevocation) {
msg := portal.bridge.DB.Message.GetByJID(portal.Key, message.Id)
if msg == nil {
return
}
var intent *appservice.IntentAPI
if message.FromMe {
if portal.IsPrivateChat() {
intent = portal.bridge.GetPuppetByJID(user.JID).CustomIntent()
} else {
intent = portal.bridge.GetPuppetByJID(user.JID).IntentFor(portal)
}
} else if len(message.Participant) > 0 {
intent = portal.bridge.GetPuppetByJID(message.Participant).IntentFor(portal)
}
if intent == nil {
intent = portal.MainIntent()
}
_, err := intent.RedactEvent(portal.MXID, msg.MXID)
if err != nil {
portal.log.Errorln("Failed to redact %s: %v", msg.JID, err)
return
}
msg.Delete()
}
//func (portal *Portal) HandleMessageRevoke(user *User, message whatsappExt.MessageRevocation) {
// msg := portal.bridge.DB.Message.GetByJID(portal.Key, message.Id)
// if msg == nil {
// return
// }
// var intent *appservice.IntentAPI
// if message.FromMe {
// if portal.IsPrivateChat() {
// intent = portal.bridge.GetPuppetByJID(user.JID).CustomIntent()
// } else {
// intent = portal.bridge.GetPuppetByJID(user.JID).IntentFor(portal)
// }
// } else if len(message.Participant) > 0 {
// intent = portal.bridge.GetPuppetByJID(message.Participant).IntentFor(portal)
// }
// if intent == nil {
// intent = portal.MainIntent()
// }
// _, err := intent.RedactEvent(portal.MXID, msg.MXID)
// if err != nil {
// portal.log.Errorln("Failed to redact %s: %v", msg.JID, err)
// return
// }
// msg.Delete()
//}
func (portal *Portal) HandleFakeMessage(source *User, message FakeMessage) {
if portal.isRecentlyHandled(message.ID) {
@ -1579,7 +1581,7 @@ func (portal *Portal) HandleMediaMessageSkype(source *User, download func(conn *
}
data, mediaMessage, err := download(source.Conn.Conn, mediaType)
if err == whatsapp.ErrMediaDownloadFailedWith404 || err == whatsapp.ErrMediaDownloadFailedWith410 {
if err == skype.ErrMediaDownloadFailedWith404 || err == skype.ErrMediaDownloadFailedWith410 {
portal.log.Warnfln("Failed to download media for %s: %v. Calling LoadMediaInfo and retrying download...", info.Id, err)
//_, err = source.Conn.LoadMediaInfo(info.RemoteJid, info.Id, info.FromMe)
//if err != nil {
@ -1588,7 +1590,7 @@ func (portal *Portal) HandleMediaMessageSkype(source *User, download func(conn *
//}
data, mediaMessage, err = download(source.Conn.Conn, mediaType)
}
if err == whatsapp.ErrNoURLPresent {
if err == skype.ErrNoURLPresent {
portal.log.Debugfln("No URL present error for media message %s, ignoring...", info.Id)
return
} else if err != nil {
@ -1819,54 +1821,6 @@ func (portal *Portal) preprocessMatrixMediaSkype(relaybotFormatted bool, content
return caption, uint64(len(data)), data
}
func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool, content *event.MessageEventContent, eventID id.EventID, mediaType whatsapp.MediaType) *MediaUpload {
//var caption string
//if relaybotFormatted {
// caption = portal.bridge.Formatter.ParseMatrix(content.FormattedBody)
//}
var file *event.EncryptedFileInfo
rawMXC := content.URL
if content.File != nil {
file = content.File
rawMXC = file.URL
}
mxc, err := rawMXC.Parse()
if err != nil {
portal.log.Errorln("Malformed content URL in %s: %v", eventID, err)
return nil
}
data, err := portal.MainIntent().DownloadBytes(mxc)
if err != nil {
portal.log.Errorfln("Failed to download media in %s: %v", eventID, err)
return nil
}
if file != nil {
data, err = file.Decrypt(data)
if err != nil {
portal.log.Errorfln("Failed to decrypt media in %s: %v", eventID, err)
return nil
}
}
//url, mediaKey, fileEncSHA256, fileSHA256, fileLength, err := sender.Conn.Upload(bytes.NewReader(data), mediaType)
//if err != nil {
// portal.log.Errorfln("Failed to upload media in %s: %v", eventID, err)
// return nil
//}
//
//return &MediaUpload{
// Caption: caption,
// URL: url,
// MediaKey: mediaKey,
// FileEncSHA256: fileEncSHA256,
// FileSHA256: fileSHA256,
// FileLength: fileLength,
// Thumbnail: portal.downloadThumbnail(content, eventID),
//}
return nil
}
type MediaUpload struct {
Caption string
URL string
@ -2098,145 +2052,6 @@ func (portal *Portal) convertMatrixMessageSkype(sender *User, evt *event.Event)
return info, sender, content
}
func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waProto.WebMessageInfo, *User, *event.MessageEventContent) {
content, ok := evt.Content.Parsed.(*event.MessageEventContent)
if !ok {
portal.log.Debugfln("Failed to handle event %s: unexpected parsed content type %T", evt.ID, evt.Content.Parsed)
return nil, sender, content
}
ts := uint64(evt.Timestamp / 1000)
status := waProto.WebMessageInfo_ERROR
fromMe := true
info := &waProto.WebMessageInfo{
Key: &waProto.MessageKey{
FromMe: &fromMe,
Id: makeMessageID(),
RemoteJid: &portal.Key.JID,
},
MessageTimestamp: &ts,
Message: &waProto.Message{},
Status: &status,
}
//ctxInfo := &waProto.ContextInfo{}
replyToID := content.GetReplyTo()
if len(replyToID) > 0 {
content.RemoveReplyFallback()
msg := portal.bridge.DB.Message.GetByMXID(replyToID)
//if msg != nil && msg.Content != nil {
if msg != nil {
//ctxInfo.StanzaId = &msg.JID
//ctxInfo.Participant = &msg.Sender
//ctxInfo.QuotedMessage = msg.Content
}
}
relaybotFormatted := false
if sender.NeedsRelaybot(portal) {
if !portal.HasRelaybot() {
if sender.HasSession() {
portal.log.Debugln("Database says", sender.MXID, "not in chat and no relaybot, but trying to send anyway")
} else {
portal.log.Debugln("Ignoring message from", sender.MXID, "in chat with no relaybot")
return nil, sender, content
}
} else {
relaybotFormatted = portal.addRelaybotFormat(sender, content)
sender = portal.bridge.Relaybot
}
}
if evt.Type == event.EventSticker {
content.MsgType = event.MsgImage
}
fmt.Println("convertMatrixMessage content.MsgType: ", content.MsgType)
switch content.MsgType {
case event.MsgText, event.MsgEmote, event.MsgNotice:
text := content.Body
if content.Format == event.FormatHTML {
text = portal.bridge.Formatter.ParseMatrix(content.FormattedBody)
}
if content.MsgType == event.MsgEmote && !relaybotFormatted {
text = "/me " + text
}
//ctxInfo.MentionedJid = mentionRegex.FindAllString(text, -1)
//for index, mention := range ctxInfo.MentionedJid {
// ctxInfo.MentionedJid[index] = mention[1:] + whatsappExt.NewUserSuffix
//}
//if ctxInfo.StanzaId != nil || ctxInfo.MentionedJid != nil {
// info.Message.ExtendedTextMessage = &waProto.ExtendedTextMessage{
// Text: &text,
// ContextInfo: ctxInfo,
// }
//} else {
// info.Message.Conversation = &text
//}
case event.MsgImage:
media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaImage)
if media == nil {
return nil, sender, content
}
info.Message.ImageMessage = &waProto.ImageMessage{
Caption: &media.Caption,
JpegThumbnail: media.Thumbnail,
Url: &media.URL,
MediaKey: media.MediaKey,
Mimetype: &content.GetInfo().MimeType,
FileEncSha256: media.FileEncSHA256,
FileSha256: media.FileSHA256,
FileLength: &media.FileLength,
}
case event.MsgVideo:
media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaVideo)
if media == nil {
return nil, sender, content
}
duration := uint32(content.GetInfo().Duration)
info.Message.VideoMessage = &waProto.VideoMessage{
Caption: &media.Caption,
JpegThumbnail: media.Thumbnail,
Url: &media.URL,
MediaKey: media.MediaKey,
Mimetype: &content.GetInfo().MimeType,
Seconds: &duration,
FileEncSha256: media.FileEncSHA256,
FileSha256: media.FileSHA256,
FileLength: &media.FileLength,
}
case event.MsgAudio:
media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaAudio)
if media == nil {
return nil, sender, content
}
duration := uint32(content.GetInfo().Duration)
info.Message.AudioMessage = &waProto.AudioMessage{
Url: &media.URL,
MediaKey: media.MediaKey,
Mimetype: &content.GetInfo().MimeType,
Seconds: &duration,
FileEncSha256: media.FileEncSHA256,
FileSha256: media.FileSHA256,
FileLength: &media.FileLength,
}
case event.MsgFile:
media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaDocument)
if media == nil {
return nil, sender, content
}
info.Message.DocumentMessage = &waProto.DocumentMessage{
Url: &media.URL,
FileName: &content.Body,
MediaKey: media.MediaKey,
Mimetype: &content.GetInfo().MimeType,
FileEncSha256: media.FileEncSHA256,
FileSha256: media.FileSHA256,
FileLength: &media.FileLength,
}
default:
portal.log.Debugln("Unhandled Matrix event %s: unknown msgtype %s", evt.ID, content.MsgType)
return nil, sender, content
}
return info, sender, content
}
func (portal *Portal) wasMessageSent(sender *User, id string) bool {
//_, err := sender.Conn.LoadMessagesAfter(portal.Key.JID, id, true, 0)
//if err != nil {

View File

@ -15,7 +15,7 @@ import (
"github.com/kelaresg/matrix-skype/database"
"github.com/kelaresg/matrix-skype/types"
"github.com/kelaresg/matrix-skype/whatsapp-ext"
//"github.com/kelaresg/matrix-skype/whatsapp-ext"
)
func (bridge *Bridge) ParsePuppetMXID(mxid id.UserID) (types.SkypeID, bool) {
@ -134,10 +134,8 @@ func (bridge *Bridge) NewPuppet(dbPuppet *database.Puppet) *Puppet {
MXID: id.NewUserID(
bridge.Config.Bridge.FormatUsername(
// dbPuppet.JID,
//),
strings.Replace(
strings.Replace(dbPuppet.JID, whatsappExt.NewUserSuffix, "", 1),
strings.Replace(dbPuppet.JID, skypeExt.NewUserSuffix, "", 1),
":",
"-",
-1,
@ -164,7 +162,7 @@ type Puppet struct {
}
func (puppet *Puppet) PhoneNumber() string {
return strings.Replace(puppet.JID, whatsappExt.NewUserSuffix, "", 1)
return strings.Replace(puppet.JID, skypeExt.NewUserSuffix, "", 1)
}
func (puppet *Puppet) IntentFor(portal *Portal) *appservice.IntentAPI {
@ -272,7 +270,7 @@ func (puppet *Puppet) UpdateName(source *User, contact skype.Contact) bool {
func (puppet *Puppet) updatePortalMeta(meta func(portal *Portal)) {
if puppet.bridge.Config.Bridge.PrivateChatPortalMeta {
jid := strings.Replace(puppet.JID, whatsappExt.NewUserSuffix, "", 1)
jid := strings.Replace(puppet.JID, skypeExt.NewUserSuffix, "", 1)
for _, portal := range puppet.bridge.GetAllPortalsByJID(jid) {
meta(portal)
}

View File

@ -18,9 +18,8 @@ package skypeExt
import (
"encoding/json"
skype "github.com/kelaresg/go-skypeapi"
"strings"
"github.com/Rhymen/go-whatsapp"
)
type ChatUpdateCommand string
@ -155,7 +154,7 @@ func (cud *ChatUpdateData) UnmarshalJSON(data []byte) error {
}
type ChatUpdateHandler interface {
whatsapp.Handler
skype.Handler
HandleChatUpdate(ChatUpdate)
}

View File

@ -18,9 +18,8 @@ package skypeExt
import (
"encoding/json"
skype "github.com/kelaresg/go-skypeapi"
"strings"
"github.com/Rhymen/go-whatsapp"
)
type CommandType string
@ -41,7 +40,7 @@ type Command struct {
}
type CommandHandler interface {
whatsapp.Handler
skype.Handler
HandleCommand(Command)
}

242
user.go
View File

@ -12,20 +12,20 @@ import (
"sync"
"time"
"github.com/pkg/errors"
//"github.com/pkg/errors"
"github.com/skip2/go-qrcode"
log "maunium.net/go/maulogger/v2"
"maunium.net/go/mautrix"
"github.com/Rhymen/go-whatsapp"
waProto "github.com/Rhymen/go-whatsapp/binary/proto"
//"github.com/Rhymen/go-whatsapp"
//waProto "github.com/Rhymen/go-whatsapp/binary/proto"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
"github.com/kelaresg/matrix-skype/database"
"github.com/kelaresg/matrix-skype/types"
"github.com/kelaresg/matrix-skype/whatsapp-ext"
//"github.com/kelaresg/matrix-skype/whatsapp-ext"
)
type User struct {
@ -587,13 +587,13 @@ func (user *User) syncPortals(chatMap map[string]skype.Conversation, createAll b
}
}
func (user *User) HandleContactList(contacts []whatsapp.Contact) {
contactMap := make(map[string]whatsapp.Contact)
for _, contact := range contacts {
contactMap[contact.Jid] = contact
}
// go user.syncPuppets(contactMap)
}
//func (user *User) HandleContactList(contacts []whatsapp.Contact) {
// contactMap := make(map[string]whatsapp.Contact)
// for _, contact := range contacts {
// contactMap[contact.Jid] = contact
// }
// // go user.syncPuppets(contactMap)
//}
func (user *User) syncPuppets(contacts map[string]skype.Contact) {
if contacts == nil {
@ -636,20 +636,6 @@ func (user *User) updateLastConnectionIfNecessary() {
}
func (user *User) HandleError(err error) {
if errors.Cause(err) != whatsapp.ErrInvalidWsData {
user.log.Errorfln("WhatsApp error: %v", err)
}
if closed, ok := err.(*whatsapp.ErrConnectionClosed); ok {
if closed.Code == 1000 && user.cleanDisconnection {
user.cleanDisconnection = false
user.log.Infoln("Clean disconnection by server")
return
}
go user.tryReconnect(fmt.Sprintf("Your WhatsApp connection was closed with websocket status code %d", closed.Code))
} else if failed, ok := err.(*whatsapp.ErrConnectionFailed); ok {
user.ConnectionErrors++
go user.tryReconnect(fmt.Sprintf("Your WhatsApp connection failed: %v", failed.Err))
}
// Otherwise unknown error, probably mostly harmless
}
@ -762,21 +748,21 @@ func (user *User) HandleImageMessage(message skype.Resource) {
user.putMessage(PortalMessage{message.Jid, user, message, uint64(message.Timestamp)})
}
func (user *User) HandleStickerMessage(message whatsapp.StickerMessage) {
user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp})
}
func (user *User) HandleVideoMessage(message whatsapp.VideoMessage) {
user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp})
}
func (user *User) HandleAudioMessage(message whatsapp.AudioMessage) {
user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp})
}
func (user *User) HandleDocumentMessage(message whatsapp.DocumentMessage) {
user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp})
}
//func (user *User) HandleStickerMessage(message whatsapp.StickerMessage) {
// user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp})
//}
//
//func (user *User) HandleVideoMessage(message whatsapp.VideoMessage) {
// user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp})
//}
//
//func (user *User) HandleAudioMessage(message whatsapp.AudioMessage) {
// user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp})
//}
//
//func (user *User) HandleDocumentMessage(message whatsapp.DocumentMessage) {
// user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp})
//}
func (user *User) HandleContactMessage(message skype.Resource) {
user.log.Debugf("HandleContactMessage: ", message)
@ -798,40 +784,40 @@ type FakeMessage struct {
Alert bool
}
func (user *User) HandleCallInfo(info whatsappExt.CallInfo) {
if info.Data != nil {
return
}
data := FakeMessage{
ID: info.ID,
}
switch info.Type {
case whatsappExt.CallOffer:
if !user.bridge.Config.Bridge.CallNotices.Start {
return
}
data.Text = "Incoming call"
data.Alert = true
case whatsappExt.CallOfferVideo:
if !user.bridge.Config.Bridge.CallNotices.Start {
return
}
data.Text = "Incoming video call"
data.Alert = true
case whatsappExt.CallTerminate:
if !user.bridge.Config.Bridge.CallNotices.End {
return
}
data.Text = "Call ended"
data.ID += "E"
default:
return
}
portal := user.GetPortalByJID(info.From)
if portal != nil {
portal.messages <- PortalMessage{info.From, user, data, 0}
}
}
//func (user *User) HandleCallInfo(info whatsappExt.CallInfo) {
// if info.Data != nil {
// return
// }
// data := FakeMessage{
// ID: info.ID,
// }
// switch info.Type {
// case whatsappExt.CallOffer:
// if !user.bridge.Config.Bridge.CallNotices.Start {
// return
// }
// data.Text = "Incoming call"
// data.Alert = true
// case whatsappExt.CallOfferVideo:
// if !user.bridge.Config.Bridge.CallNotices.Start {
// return
// }
// data.Text = "Incoming video call"
// data.Alert = true
// case whatsappExt.CallTerminate:
// if !user.bridge.Config.Bridge.CallNotices.End {
// return
// }
// data.Text = "Call ended"
// data.ID += "E"
// default:
// return
// }
// portal := user.GetPortalByJID(info.From)
// if portal != nil {
// portal.messages <- PortalMessage{info.From, user, data, 0}
// }
//}
func (user *User) HandleTypingStatus(info skype.Resource) {
sendId := info.SendId + skypeExt.NewUserSuffix
@ -904,62 +890,62 @@ func (user *User) HandlePresence(info skype.Resource) {
}
}
func (user *User) HandlePresenceWA(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
}
_ = 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)
_ = puppet.DefaultIntent().SetPresence("online")
}
}
//func (user *User) HandlePresenceWA(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
// }
// _ = 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)
// _ = puppet.DefaultIntent().SetPresence("online")
// }
//}
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 _, id := range info.IDs {
msg := user.bridge.DB.Message.GetByJID(portal.Key, id)
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
// }
//
// go func() {
// intent := user.bridge.GetPuppetByJID(info.SenderJID).IntentFor(portal)
// for _, id := range info.IDs {
// msg := user.bridge.DB.Message.GetByJID(portal.Key, id)
// 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) HandleCommand(cmd skypeExt.Command) {
switch cmd.Type {
case skypeExt.CommandPicture:
if strings.HasSuffix(cmd.JID, whatsappExt.NewUserSuffix) {
if strings.HasSuffix(cmd.JID, skypeExt.NewUserSuffix) {
puppet := user.bridge.GetPuppetByJID(cmd.JID)
go puppet.UpdateAvatar(user, cmd.ProfilePicInfo)
} else {
@ -1145,9 +1131,9 @@ func (user *User) HandleJsonMessage(message string) {
user.updateLastConnectionIfNecessary()
}
func (user *User) HandleRawMessage(message *waProto.WebMessageInfo) {
user.updateLastConnectionIfNecessary()
}
//func (user *User) HandleRawMessage(message *waProto.WebMessageInfo) {
// user.updateLastConnectionIfNecessary()
//}
func (user *User) NeedsRelaybot(portal *Portal) bool {
return false

View File

@ -1,72 +0,0 @@
// matrix-skype - A Matrix-WhatsApp puppeting bridge.
// Copyright (C) 2019 Tulir Asokan
//
// 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/>.
package whatsappExt
import (
"encoding/json"
"strings"
"github.com/Rhymen/go-whatsapp"
)
type CallInfoType string
const (
CallOffer CallInfoType = "offer"
CallOfferVideo CallInfoType = "offer_video"
CallTransport CallInfoType = "transport"
CallRelayLatency CallInfoType = "relaylatency"
CallTerminate CallInfoType = "terminate"
)
type CallInfo struct {
ID string `json:"id"`
Type CallInfoType `json:"type"`
From string `json:"from"`
Platform string `json:"platform"`
Version []int `json:"version"`
Data [][]interface{} `json:"data"`
}
type CallInfoHandler interface {
whatsapp.Handler
HandleCallInfo(CallInfo)
}
func (ext *ExtendedConn) handleMessageCall(message []byte) {
var event CallInfo
err := json.Unmarshal(message, &event)
if err != nil {
ext.jsonParseError(err)
return
}
event.From = strings.Replace(event.From, OldUserSuffix, NewUserSuffix, 1)
for _, handler := range ext.handlers {
callInfoHandler, ok := handler.(CallInfoHandler)
if !ok {
continue
}
if ext.shouldCallSynchronously(callInfoHandler) {
callInfoHandler.HandleCallInfo(event)
} else {
go callInfoHandler.HandleCallInfo(event)
}
}
}

View File

@ -1,174 +0,0 @@
// matrix-skype - A Matrix-WhatsApp puppeting bridge.
// Copyright (C) 2019 Tulir Asokan
//
// 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/>.
package whatsappExt
import (
"encoding/json"
"strings"
"github.com/Rhymen/go-whatsapp"
)
type ChatUpdateCommand string
const (
ChatUpdateCommandAction ChatUpdateCommand = "action"
)
type ChatUpdate struct {
JID string `json:"id"`
Command ChatUpdateCommand `json:"cmd"`
Data ChatUpdateData `json:"data"`
}
type ChatActionType string
const (
ChatActionNameChange ChatActionType = "subject"
ChatActionAddTopic ChatActionType = "desc_add"
ChatActionRemoveTopic ChatActionType = "desc_remove"
ChatActionRestrict ChatActionType = "restrict"
ChatActionAnnounce ChatActionType = "announce"
ChatActionPromote ChatActionType = "promote"
ChatActionDemote ChatActionType = "demote"
ChatActionRemove ChatActionType = "remove"
ChatActionAdd ChatActionType = "add"
ChatActionIntroduce ChatActionType = "introduce"
ChatActionCreate ChatActionType = "create"
)
type ChatUpdateData struct {
Action ChatActionType
SenderJID string
NameChange struct {
Name string `json:"subject"`
SetAt int64 `json:"s_t"`
SetBy string `json:"s_o"`
}
AddTopic struct {
Topic string `json:"desc"`
ID string `json:"descId"`
SetAt int64 `json:"descTime"`
}
RemoveTopic struct {
ID string `json:"descId"`
}
Restrict bool
Announce bool
PermissionChange struct {
JIDs []string `json:"participants"`
}
MemberAction struct {
JIDs []string `json:"participants"`
}
Create struct {
Creation int64 `json:"creation"`
Name string `json:"subject"`
SetAt int64 `json:"s_t"`
SetBy string `json:"s_o"`
Admins []string `json:"admins"`
SuperAdmins []string `json:"superadmins"`
Regulars []string `json:"regulars"`
}
}
func (cud *ChatUpdateData) UnmarshalJSON(data []byte) error {
var arr []json.RawMessage
err := json.Unmarshal(data, &arr)
if err != nil {
return err
} else if len(arr) < 3 {
return nil
}
err = json.Unmarshal(arr[0], &cud.Action)
if err != nil {
return err
}
err = json.Unmarshal(arr[1], &cud.SenderJID)
if err != nil {
return err
}
cud.SenderJID = strings.Replace(cud.SenderJID, OldUserSuffix, NewUserSuffix, 1)
var unmarshalTo interface{}
switch cud.Action {
case ChatActionNameChange:
unmarshalTo = &cud.NameChange
case ChatActionAddTopic:
unmarshalTo = &cud.AddTopic
case ChatActionRemoveTopic:
unmarshalTo = &cud.RemoveTopic
case ChatActionRestrict:
unmarshalTo = &cud.Restrict
case ChatActionAnnounce:
unmarshalTo = &cud.Announce
case ChatActionPromote, ChatActionDemote:
unmarshalTo = &cud.PermissionChange
case ChatActionAdd, ChatActionRemove:
unmarshalTo = &cud.MemberAction
case ChatActionCreate:
unmarshalTo = &cud.Create
default:
return nil
}
err = json.Unmarshal(arr[2], unmarshalTo)
if err != nil {
return err
}
cud.NameChange.SetBy = strings.Replace(cud.NameChange.SetBy, OldUserSuffix, NewUserSuffix, 1)
for index, jid := range cud.PermissionChange.JIDs {
cud.PermissionChange.JIDs[index] = strings.Replace(jid, OldUserSuffix, NewUserSuffix, 1)
}
return nil
}
type ChatUpdateHandler interface {
whatsapp.Handler
HandleChatUpdate(ChatUpdate)
}
func (ext *ExtendedConn) handleMessageChatUpdate(message []byte) {
var event ChatUpdate
err := json.Unmarshal(message, &event)
if err != nil {
ext.jsonParseError(err)
return
}
event.JID = strings.Replace(event.JID, OldUserSuffix, NewUserSuffix, 1)
for _, handler := range ext.handlers {
chatUpdateHandler, ok := handler.(ChatUpdateHandler)
if !ok {
continue
}
if ext.shouldCallSynchronously(chatUpdateHandler) {
chatUpdateHandler.HandleChatUpdate(event)
} else {
go chatUpdateHandler.HandleChatUpdate(event)
}
}
}

View File

@ -1,69 +0,0 @@
// matrix-skype - A Matrix-WhatsApp puppeting bridge.
// Copyright (C) 2019 Tulir Asokan
//
// 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/>.
package whatsappExt
import (
"encoding/json"
"strings"
"github.com/Rhymen/go-whatsapp"
)
type CommandType string
const (
CommandPicture CommandType = "picture"
CommandDisconnect CommandType = "disconnect"
)
type Command struct {
Type CommandType `json:"type"`
JID string `json:"jid"`
*ProfilePicInfo
Kind string `json:"kind"`
Raw json.RawMessage `json:"-"`
}
type CommandHandler interface {
whatsapp.Handler
HandleCommand(Command)
}
func (ext *ExtendedConn) handleMessageCommand(message []byte) {
var event Command
err := json.Unmarshal(message, &event)
if err != nil {
ext.jsonParseError(err)
return
}
event.Raw = message
event.JID = strings.Replace(event.JID, OldUserSuffix, NewUserSuffix, 1)
for _, handler := range ext.handlers {
commandHandler, ok := handler.(CommandHandler)
if !ok {
continue
}
if ext.shouldCallSynchronously(commandHandler) {
commandHandler.HandleCommand(event)
} else {
go commandHandler.HandleCommand(event)
}
}
}

View File

@ -1,65 +0,0 @@
// matrix-skype - A Matrix-WhatsApp puppeting bridge.
// Copyright (C) 2019 Tulir Asokan
//
// 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/>.
package whatsappExt
import (
"encoding/json"
"github.com/Rhymen/go-whatsapp"
)
type ConnInfo struct {
ProtocolVersion []int `json:"protoVersion"`
BinaryVersion int `json:"binVersion"`
Phone struct {
WhatsAppVersion string `json:"wa_version"`
MCC string `json:"mcc"`
MNC string `json:"mnc"`
OSVersion string `json:"os_version"`
DeviceManufacturer string `json:"device_manufacturer"`
DeviceModel string `json:"device_model"`
OSBuildNumber string `json:"os_build_number"`
} `json:"phone"`
Features map[string]interface{} `json:"features"`
PushName string `json:"pushname"`
}
type ConnInfoHandler interface {
whatsapp.Handler
HandleConnInfo(ConnInfo)
}
func (ext *ExtendedConn) handleMessageConn(message []byte) {
var event ConnInfo
err := json.Unmarshal(message, &event)
if err != nil {
ext.jsonParseError(err)
return
}
for _, handler := range ext.handlers {
connInfoHandler, ok := handler.(ConnInfoHandler)
if !ok {
continue
}
if ext.shouldCallSynchronously(connInfoHandler) {
connInfoHandler.HandleConnInfo(event)
} else {
go connInfoHandler.HandleConnInfo(event)
}
}
}

View File

@ -1,105 +0,0 @@
// matrix-skype - A Matrix-WhatsApp puppeting bridge.
// Copyright (C) 2019 Tulir Asokan
//
// 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/>.
package whatsappExt
import (
"encoding/json"
"github.com/Rhymen/go-whatsapp"
)
type JSONMessage []json.RawMessage
type JSONMessageType string
const (
MessageMsgInfo JSONMessageType = "MsgInfo"
MessageMsg JSONMessageType = "Msg"
MessagePresence JSONMessageType = "Presence"
MessageStream JSONMessageType = "Stream"
MessageConn JSONMessageType = "Conn"
MessageProps JSONMessageType = "Props"
MessageCmd JSONMessageType = "Cmd"
MessageChat JSONMessageType = "Chat"
MessageCall JSONMessageType = "Call"
)
func (ext *ExtendedConn) HandleError(error) {}
type UnhandledJSONMessageHandler interface {
whatsapp.Handler
HandleUnhandledJSONMessage(string)
}
type JSONParseErrorHandler interface {
whatsapp.Handler
HandleJSONParseError(error)
}
func (ext *ExtendedConn) jsonParseError(err error) {
for _, handler := range ext.handlers {
errorHandler, ok := handler.(JSONParseErrorHandler)
if !ok {
continue
}
errorHandler.HandleJSONParseError(err)
}
}
func (ext *ExtendedConn) HandleJsonMessage(message string) {
msg := JSONMessage{}
err := json.Unmarshal([]byte(message), &msg)
if err != nil || len(msg) < 2 {
ext.jsonParseError(err)
return
}
var msgType JSONMessageType
json.Unmarshal(msg[0], &msgType)
switch msgType {
case MessagePresence:
ext.handleMessagePresence(msg[1])
case MessageStream:
ext.handleMessageStream(msg[1:])
case MessageConn:
ext.handleMessageConn(msg[1])
case MessageProps:
ext.handleMessageProps(msg[1])
case MessageMsgInfo, MessageMsg:
ext.handleMessageMsgInfo(msgType, msg[1])
case MessageCmd:
ext.handleMessageCommand(msg[1])
case MessageChat:
ext.handleMessageChatUpdate(msg[1])
case MessageCall:
ext.handleMessageCall(msg[1])
default:
for _, handler := range ext.handlers {
ujmHandler, ok := handler.(UnhandledJSONMessageHandler)
if !ok {
continue
}
if ext.shouldCallSynchronously(ujmHandler) {
ujmHandler.HandleUnhandledJSONMessage(message)
} else {
go ujmHandler.HandleUnhandledJSONMessage(message)
}
}
}
}

View File

@ -1,95 +0,0 @@
// matrix-skype - A Matrix-WhatsApp puppeting bridge.
// Copyright (C) 2019 Tulir Asokan
//
// 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/>.
package whatsappExt
import (
"encoding/json"
"strings"
"github.com/Rhymen/go-whatsapp"
)
type MsgInfoCommand string
const (
MsgInfoCommandAck MsgInfoCommand = "ack"
MsgInfoCommandAcks MsgInfoCommand = "acks"
)
type Acknowledgement int
const (
AckMessageSent Acknowledgement = 1
AckMessageDelivered Acknowledgement = 2
AckMessageRead Acknowledgement = 3
)
type JSONStringOrArray []string
func (jsoa *JSONStringOrArray) UnmarshalJSON(data []byte) error {
var str string
if json.Unmarshal(data, &str) == nil {
*jsoa = []string{str}
return nil
}
var strs []string
json.Unmarshal(data, &strs)
*jsoa = strs
return nil
}
type MsgInfo struct {
Command MsgInfoCommand `json:"cmd"`
IDs JSONStringOrArray `json:"id"`
Acknowledgement Acknowledgement `json:"ack"`
MessageFromJID string `json:"from"`
SenderJID string `json:"participant"`
ToJID string `json:"to"`
Timestamp int64 `json:"t"`
}
type MsgInfoHandler interface {
whatsapp.Handler
HandleMsgInfo(MsgInfo)
}
func (ext *ExtendedConn) handleMessageMsgInfo(msgType JSONMessageType, message []byte) {
var event MsgInfo
err := json.Unmarshal(message, &event)
if err != nil {
ext.jsonParseError(err)
return
}
event.MessageFromJID = strings.Replace(event.MessageFromJID, OldUserSuffix, NewUserSuffix, 1)
event.SenderJID = strings.Replace(event.SenderJID, OldUserSuffix, NewUserSuffix, 1)
event.ToJID = strings.Replace(event.ToJID, OldUserSuffix, NewUserSuffix, 1)
if msgType == MessageMsg {
event.SenderJID = event.ToJID
}
for _, handler := range ext.handlers {
msgInfoHandler, ok := handler.(MsgInfoHandler)
if !ok {
continue
}
if ext.shouldCallSynchronously(msgInfoHandler) {
msgInfoHandler.HandleMsgInfo(event)
} else {
go msgInfoHandler.HandleMsgInfo(event)
}
}
}

View File

@ -1,67 +0,0 @@
// matrix-skype - A Matrix-WhatsApp puppeting bridge.
// Copyright (C) 2019 Tulir Asokan
//
// 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/>.
package whatsappExt
import (
"encoding/json"
"strings"
"github.com/Rhymen/go-whatsapp"
)
type Presence struct {
JID string `json:"id"`
SenderJID string `json:"participant"`
Status whatsapp.Presence `json:"type"`
Timestamp int64 `json:"t"`
Deny bool `json:"deny"`
}
type PresenceHandler interface {
whatsapp.Handler
HandlePresence(Presence)
}
func (ext *ExtendedConn) handleMessagePresence(message []byte) {
var event Presence
err := json.Unmarshal(message, &event)
if err != nil {
ext.jsonParseError(err)
return
}
event.JID = strings.Replace(event.JID, OldUserSuffix, NewUserSuffix, 1)
if len(event.SenderJID) == 0 {
if strings.Index(event.JID,"@g.us") > -1 {
return
}
event.SenderJID = event.JID
} else {
event.SenderJID = strings.Replace(event.SenderJID, OldUserSuffix, NewUserSuffix, 1)
}
for _, handler := range ext.handlers {
presenceHandler, ok := handler.(PresenceHandler)
if !ok {
continue
}
if ext.shouldCallSynchronously(presenceHandler) {
presenceHandler.HandlePresence(event)
} else {
go presenceHandler.HandlePresence(event)
}
}
}

View File

@ -1,73 +0,0 @@
// matrix-skype - A Matrix-WhatsApp puppeting bridge.
// Copyright (C) 2019 Tulir Asokan
//
// 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/>.
package whatsappExt
import (
"encoding/json"
"github.com/Rhymen/go-whatsapp"
)
type ProtocolProps struct {
WebPresence bool `json:"webPresence"`
NotificationQuery bool `json:"notificationQuery"`
FacebookCrashLog bool `json:"fbCrashlog"`
Bucket string `json:"bucket"`
GIFSearch string `json:"gifSearch"`
Spam bool `json:"SPAM"`
SetBlock bool `json:"SET_BLOCK"`
MessageInfo bool `json:"MESSAGE_INFO"`
MaxFileSize int `json:"maxFileSize"`
Media int `json:"media"`
GroupNameLength int `json:"maxSubject"`
GroupDescriptionLength int `json:"groupDescLength"`
MaxParticipants int `json:"maxParticipants"`
VideoMaxEdge int `json:"videoMaxEdge"`
ImageMaxEdge int `json:"imageMaxEdge"`
ImageMaxKilobytes int `json:"imageMaxKBytes"`
Edit int `json:"edit"`
FwdUIStartTimestamp int `json:"fwdUiStartTs"`
GroupsV3 int `json:"groupsV3"`
RestrictGroups int `json:"restrictGroups"`
AnnounceGroups int `json:"announceGroups"`
}
type ProtocolPropsHandler interface {
whatsapp.Handler
HandleProtocolProps(ProtocolProps)
}
func (ext *ExtendedConn) handleMessageProps(message []byte) {
var event ProtocolProps
err := json.Unmarshal(message, &event)
if err != nil {
ext.jsonParseError(err)
return
}
for _, handler := range ext.handlers {
protocolPropsHandler, ok := handler.(ProtocolPropsHandler)
if !ok {
continue
}
if ext.shouldCallSynchronously(protocolPropsHandler) {
protocolPropsHandler.HandleProtocolProps(event)
} else {
go protocolPropsHandler.HandleProtocolProps(event)
}
}
}

View File

@ -1,59 +0,0 @@
// matrix-skype - A Matrix-WhatsApp puppeting bridge.
// Copyright (C) 2019 Tulir Asokan
//
// 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/>.
package whatsappExt
import (
"github.com/Rhymen/go-whatsapp"
"github.com/Rhymen/go-whatsapp/binary/proto"
)
type MessageRevokeHandler interface {
whatsapp.Handler
HandleMessageRevoke(key MessageRevocation)
}
type MessageRevocation struct {
Id string
RemoteJid string
FromMe bool
Participant string
}
func (ext *ExtendedConn) HandleRawMessage(message *proto.WebMessageInfo) {
protoMsg := message.GetMessage().GetProtocolMessage()
if protoMsg != nil && protoMsg.GetType() == proto.ProtocolMessage_REVOKE {
key := protoMsg.GetKey()
deletedMessage := MessageRevocation{
Id: key.GetId(),
RemoteJid: key.GetRemoteJid(),
FromMe: key.GetFromMe(),
Participant: key.GetParticipant(),
}
for _, handler := range ext.handlers {
mrHandler, ok := handler.(MessageRevokeHandler)
if !ok {
continue
}
if ext.shouldCallSynchronously(mrHandler) {
mrHandler.HandleMessageRevoke(deletedMessage)
} else {
go mrHandler.HandleMessageRevoke(deletedMessage)
}
}
}
}

View File

@ -1,68 +0,0 @@
// matrix-skype - A Matrix-WhatsApp puppeting bridge.
// Copyright (C) 2019 Tulir Asokan
//
// 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/>.
package whatsappExt
import (
"encoding/json"
"github.com/Rhymen/go-whatsapp"
)
type StreamType string
const (
StreamUpdate = "update"
StreamSleep = "asleep"
)
type StreamEvent struct {
Type StreamType
Boolean bool
Version string
}
type StreamEventHandler interface {
whatsapp.Handler
HandleStreamEvent(StreamEvent)
}
func (ext *ExtendedConn) handleMessageStream(message []json.RawMessage) {
var event StreamEvent
err := json.Unmarshal(message[0], &event.Type)
if err != nil {
ext.jsonParseError(err)
return
}
if event.Type == StreamUpdate && len(message) > 4 {
json.Unmarshal(message[1], event.Boolean)
json.Unmarshal(message[2], event.Version)
}
for _, handler := range ext.handlers {
streamHandler, ok := handler.(StreamEventHandler)
if !ok {
continue
}
if ext.shouldCallSynchronously(streamHandler) {
streamHandler.HandleStreamEvent(event)
} else {
go streamHandler.HandleStreamEvent(event)
}
}
}

View File

@ -1,206 +0,0 @@
// matrix-skype - A Matrix-WhatsApp puppeting bridge.
// Copyright (C) 2019 Tulir Asokan
//
// 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/>.
package whatsappExt
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"strings"
"github.com/Rhymen/go-whatsapp"
)
const (
OldUserSuffix = "@c.us"
//NewUserSuffix = "@s.whatsapp.net"
NewUserSuffix = "@s.skype.net"
)
type ExtendedConn struct {
*whatsapp.Conn
handlers []whatsapp.Handler
}
func ExtendConn(conn *whatsapp.Conn) *ExtendedConn {
ext := &ExtendedConn{
Conn: conn,
}
ext.Conn.AddHandler(ext)
return ext
}
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)
}
func (ext *ExtendedConn) shouldCallSynchronously(handler whatsapp.Handler) bool {
sh, ok := handler.(whatsapp.SyncHandler)
return ok && sh.ShouldCallSynchronously()
}
func (ext *ExtendedConn) ShouldCallSynchronously() bool {
return true
}
type GroupInfo struct {
JID string `json:"jid"`
OwnerJID string `json:"owner"`
Name string `json:"subject"`
NameSetTime int64 `json:"subjectTime"`
NameSetBy string `json:"subjectOwner"`
Topic string `json:"desc"`
TopicID string `json:"descId"`
TopicSetAt int64 `json:"descTime"`
TopicSetBy string `json:"descOwner"`
GroupCreated int64 `json:"creation"`
Status int16 `json:"status"`
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
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 {
info.Participants[index].JID = strings.Replace(participant.JID, OldUserSuffix, NewUserSuffix, 1)
}
info.NameSetBy = strings.Replace(info.NameSetBy, OldUserSuffix, NewUserSuffix, 1)
info.TopicSetBy = strings.Replace(info.TopicSetBy, OldUserSuffix, NewUserSuffix, 1)
return info, nil
}
type ProfilePicInfo struct {
URL string `json:"eurl"`
Tag string `json:"tag"`
Status int16 `json:"status"`
}
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
}
func (ext *ExtendedConn) HandleGroupInvite(groupJid string, numbers[]string) (err error) {
var parts []string
parts = append(parts, numbers...)
_, err = ext.Conn.AddMember(groupJid, parts)
if err != nil {
fmt.Printf("%s Handle Invite err", err)
}
return
}
func (ext *ExtendedConn) HandleGroupJoin(code string) (jid string, err error) {
return ext.Conn.GroupAcceptInviteCode(code)
}
func (ext *ExtendedConn) HandleGroupKick(groupJid string, numbers[]string) (err error) {
var parts []string
parts = append(parts, numbers...)
_, err = ext.Conn.RemoveMember(groupJid, parts)
if err != nil {
fmt.Printf("%s Handle kick err", err)
}
return
}
func (ext *ExtendedConn) HandleGroupCreate(subject string, numbers[]string) (err error) {
var parts []string
parts = append(parts, numbers...)
_, err = ext.Conn.CreateGroup(subject, parts)
if err != nil {
fmt.Printf("%s HandleGroupCreate err", err)
}
return
}
func (ext *ExtendedConn) HandleGroupLeave(groupJid string) (err error) {
_, err = ext.Conn.LeaveGroup(groupJid)
if err != nil {
fmt.Printf("%s HandleGroupLeave err", err)
}
return
}