4
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2025-06-27 14:39:24 +00:00

Update dependencies (#975)

This commit is contained in:
Wim
2020-01-09 21:02:56 +01:00
committed by GitHub
parent b9354de8fd
commit 0f708daf2d
360 changed files with 72921 additions and 42691 deletions

View File

@ -23,7 +23,7 @@ qrChan := make(chan string)
go func() {
fmt.Printf("qr code: %v\n", <-qrChan)
//show qr code or save it somewhere to scan
}
}()
sess, err := wac.Login(qrChan)
```
The authentication process requires you to scan the qr code, that is send through the channel, with the device you are using whatsapp on. The session struct that is returned can be saved and used to restore the login without scanning the qr code again. The qr code has a ttl of 20 seconds and the login function throws a timeout err if the time has passed or any other request fails.
@ -66,6 +66,10 @@ func (myHandler) HandleJsonMessage(message string) {
fmt.Println(message)
}
func (myHandler) HandleContactMessage(message whatsapp.ContactMessage) {
fmt.Println(message)
}
wac.AddHandler(myHandler{})
```
The message handlers are all optional, you don't need to implement anything but the error handler to implement the interface. The ImageMessage, VideoMessage, AudioMessage and DocumentMessage provide a Download function to get the media data.
@ -81,6 +85,21 @@ text := whatsapp.TextMessage{
err := wac.Send(text)
```
### Sending Contact Messages
```go
contactMessage := whatsapp.ContactMessage{
Info: whatsapp.MessageInfo{
RemoteJid: "0123456789@s.whatsapp.net",
},
DisplayName: "Luke Skylwallker",
Vcard: "BEGIN:VCARD\nVERSION:3.0\nN:Skyllwalker;Luke;;\nFN:Luke Skywallker\nitem1.TEL;waid=0123456789:+1 23 456789789\nitem1.X-ABLabel:Mobile\nEND:VCARD",
}
id, error := client.WaConn.Send(contactMessage)
```
The message will be send over the websocket. The attributes seen above are the required ones. All other relevant attributes (id, timestamp, fromMe, status) are set if they are missing in the struct. For the time being we only support text messages, but other types are planned for the near future.
## Legal

View File

@ -66,9 +66,12 @@ func Unmarshal(data []byte) (*Node, error) {
}
if n != nil && n.Attributes != nil && n.Content != nil {
n.Content, err = unmarshalMessageArray(n.Content.([]Node))
if err != nil {
return nil, err
nContent, ok := n.Content.([]Node)
if ok {
n.Content, err = unmarshalMessageArray(nContent)
if err != nil {
return nil, err
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@ package proto;
message HydratedQuickReplyButton {
optional string displayText = 1;
optional string buttonId = 2;
optional string id = 2;
}
message HydratedURLButton {
@ -17,6 +17,7 @@ message HydratedCallButton {
}
message HydratedTemplateButton {
optional uint32 index = 4;
oneof hydratedButton {
HydratedQuickReplyButton quickReplyButton = 1;
HydratedURLButton urlButton = 2;
@ -26,7 +27,7 @@ message HydratedTemplateButton {
message QuickReplyButton {
optional HighlyStructuredMessage displayText = 1;
optional string buttonId = 2;
optional string id = 2;
}
message URLButton {
@ -40,6 +41,7 @@ message CallButton {
}
message TemplateButton {
optional uint32 index = 4;
oneof button {
QuickReplyButton quickReplyButton = 1;
URLButton urlButton = 2;
@ -89,6 +91,8 @@ message ContextInfo {
optional uint32 forwardingScore = 21;
optional bool isForwarded = 22;
optional AdReplyInfo quotedAd = 23;
optional MessageKey placeholderKey = 24;
optional uint32 expiration = 25;
}
message SenderKeyDistributionMessage {
@ -114,6 +118,10 @@ message ImageMessage {
optional bytes firstScanSidecar = 18;
optional uint32 firstScanLength = 19;
optional uint32 experimentGroupId = 20;
optional bytes scansSidecar = 21;
repeated uint32 scanLengths = 22;
optional bytes midQualityFileSha256 = 23;
optional bytes midQualityFileEncSha256 = 24;
}
message ContactMessage {
@ -156,6 +164,7 @@ message ExtendedTextMessage {
optional EXTENDED_TEXT_MESSAGE_PREVIEWTYPE previewType = 10;
optional bytes jpegThumbnail = 16;
optional ContextInfo contextInfo = 17;
optional bool doNotPlayInline = 18;
}
message DocumentMessage {
@ -228,8 +237,10 @@ message ProtocolMessage {
optional MessageKey key = 1;
enum PROTOCOL_MESSAGE_TYPE {
REVOKE = 0;
EPHEMERAL_SETTING = 3;
}
optional PROTOCOL_MESSAGE_TYPE type = 2;
optional uint32 ephemeralExpiration = 4;
}
message ContactsArrayMessage {
@ -294,6 +305,7 @@ message HighlyStructuredMessage {
repeated HSMLocalizableParameter localizableParams = 6;
optional string deterministicLg = 7;
optional string deterministicLc = 8;
optional TemplateMessage hydratedHsm = 9;
}
message SendPaymentMessage {
@ -341,7 +353,8 @@ message StickerMessage {
optional string directPath = 8;
optional uint64 fileLength = 9;
optional int64 mediaKeyTimestamp = 10;
optional bytes pngThumbnail = 16;
optional uint32 firstFrameLength = 11;
optional bytes firstFrameSidecar = 12;
optional ContextInfo contextInfo = 17;
}
@ -361,7 +374,8 @@ message FourRowTemplate {
message HydratedFourRowTemplate {
optional string hydratedContentText = 6;
optional string hydratedFooterText = 7;
repeated HydratedTemplateButton hydratedButtons = 9;
repeated HydratedTemplateButton hydratedButtons = 8;
optional string templateId = 9;
oneof title {
DocumentMessage documentMessage = 1;
string hydratedTitleText = 2;
@ -372,6 +386,8 @@ message HydratedFourRowTemplate {
}
message TemplateMessage {
optional ContextInfo contextInfo = 3;
optional HydratedFourRowTemplate hydratedTemplate = 4;
oneof format {
FourRowTemplate fourRowTemplate = 1;
HydratedFourRowTemplate hydratedFourRowTemplate = 2;
@ -379,9 +395,10 @@ message TemplateMessage {
}
message TemplateButtonReplyMessage {
optional string selectedButtonId = 1;
repeated string selectedButtonDisplayText = 2;
optional string selectedId = 1;
optional string selectedDisplayText = 2;
optional ContextInfo contextInfo = 3;
optional uint32 selectedIndex = 4;
}
message ProductSnapshot {
@ -394,6 +411,7 @@ message ProductSnapshot {
optional string retailerId = 7;
optional string url = 8;
optional uint32 productImageCount = 9;
optional string firstImageId = 11;
}
message ProductMessage {
@ -409,6 +427,16 @@ message GroupInviteMessage {
optional string groupName = 4;
optional bytes jpegThumbnail = 5;
optional string caption = 6;
optional ContextInfo contextInfo = 7;
}
message DeviceSentMessage {
optional string destinationJid = 1;
optional Message message = 2;
}
message DeviceSyncMessage {
optional bytes serializedXmlBytes = 1;
}
message Message {
@ -434,8 +462,11 @@ message Message {
optional CancelPaymentRequestMessage cancelPaymentRequestMessage = 24;
optional TemplateMessage templateMessage = 25;
optional StickerMessage stickerMessage = 26;
optional ProductMessage productMessage = 27;
optional GroupInviteMessage groupInviteMessage = 28;
optional TemplateButtonReplyMessage templateButtonReplyMessage = 29;
optional ProductMessage productMessage = 30;
optional DeviceSentMessage deviceSentMessage = 31;
optional DeviceSyncMessage deviceSyncMessage = 32;
}
message MessageKey {
@ -447,9 +478,10 @@ message MessageKey {
message WebFeatures {
enum WEB_FEATURES_FLAG {
NOT_IMPLEMENTED = 0;
IMPLEMENTED = 1;
OPTIONAL = 2;
NOT_STARTED = 0;
FORCE_UPGRADE = 1;
DEVELOPMENT = 2;
PRODUCTION = 3;
}
optional WEB_FEATURES_FLAG labelsDisplay = 1;
optional WEB_FEATURES_FLAG voipIndividualOutgoing = 2;
@ -473,6 +505,14 @@ message WebFeatures {
optional WEB_FEATURES_FLAG voipIndividualVideo = 22;
optional WEB_FEATURES_FLAG thirdPartyStickers = 23;
optional WEB_FEATURES_FLAG frequentlyForwardedSetting = 24;
optional WEB_FEATURES_FLAG groupsV4JoinPermission = 25;
optional WEB_FEATURES_FLAG recentStickers = 26;
optional WEB_FEATURES_FLAG catalog = 27;
optional WEB_FEATURES_FLAG starredStickers = 28;
optional WEB_FEATURES_FLAG voipGroupCall = 29;
optional WEB_FEATURES_FLAG templateMessage = 30;
optional WEB_FEATURES_FLAG templateMessageInteractivity = 31;
optional WEB_FEATURES_FLAG ephemeralMessages = 32;
}
message TabletNotificationsInfo {
@ -614,6 +654,9 @@ message WebMessageInfo {
BIZ_TWO_TIER_MIGRATION_BOTTOM = 67;
OVERSIZED = 68;
GROUP_CHANGE_NO_FREQUENTLY_FORWARDED = 69;
GROUP_V4_ADD_INVITE_SENT = 70;
GROUP_PARTICIPANT_ADD_REQUEST_JOIN = 71;
CHANGE_EPHEMERAL_SETTING = 72;
}
optional WEB_MESSAGE_INFO_STUBTYPE messageStubType = 24;
optional bool clearMedia = 25;
@ -623,4 +666,6 @@ message WebMessageInfo {
optional PaymentInfo paymentInfo = 29;
optional LiveLocationMessage finalLiveLocation = 30;
optional PaymentInfo quotedPaymentInfo = 31;
}
optional uint64 ephemeralStartTimestamp = 32;
optional uint32 ephemeralDuration = 33;
}

View File

@ -93,6 +93,8 @@ type Conn struct {
loginSessionLock sync.RWMutex
Proxy func(*http.Request) (*url.URL, error)
writerLock sync.RWMutex
}
type websocketWrapper struct {

View File

@ -10,11 +10,11 @@ import (
type Presence string
const (
PresenceAvailable = "available"
PresenceUnavailable = "unavailable"
PresenceComposing = "composing"
PresenceRecording = "recording"
PresencePaused = "paused"
PresenceAvailable Presence = "available"
PresenceUnavailable Presence = "unavailable"
PresenceComposing Presence = "composing"
PresenceRecording Presence = "recording"
PresencePaused Presence = "paused"
)
//TODO: filename? WhatsApp uses Store.Contacts for these functions

View File

@ -10,3 +10,5 @@ require (
github.com/pkg/errors v0.8.1
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
)
go 1.13

View File

@ -82,13 +82,21 @@ type LocationMessageHandler interface {
}
/*
The StickerMessageHandler interface needs to be implemented to receive location messages dispatched by the dispatcher.
The StickerMessageHandler interface needs to be implemented to receive sticker messages dispatched by the dispatcher.
*/
type StickerMessageHandler interface {
Handler
HandleStickerMessage(message StickerMessage)
}
/*
The ContactMessageHandler interface needs to be implemented to receive contact messages dispatched by the dispatcher.
*/
type ContactMessageHandler interface {
Handler
HandleContactMessage(message ContactMessage)
}
/*
The JsonMessageHandler interface needs to be implemented to receive json messages dispatched by the dispatcher.
These json messages contain status updates of every kind sent by WhatsAppWeb servers. WhatsAppWeb uses these messages
@ -267,6 +275,17 @@ func (wac *Conn) handleWithCustomHandlers(message interface{}, handlers []Handle
}
}
case ContactMessage:
for _, h := range handlers {
if x, ok := h.(ContactMessageHandler); ok {
if wac.shouldCallSynchronously(h) {
x.HandleContactMessage(m)
} else {
go x.HandleContactMessage(m)
}
}
}
case *proto.WebMessageInfo:
for _, h := range handlers {
if x, ok := h.(RawMessageHandler); ok {

View File

@ -23,64 +23,53 @@ const (
MediaDocument MediaType = "WhatsApp Document Keys"
)
var msgInfo MessageInfo
func (wac *Conn) Send(msg interface{}) (string, error) {
var err error
var ch <-chan string
var msgProto *proto.WebMessageInfo
switch m := msg.(type) {
case *proto.WebMessageInfo:
ch, err = wac.sendProto(m)
msgProto = m
case TextMessage:
msgProto = getTextProto(m)
msgInfo = getMessageInfo(msgProto)
ch, err = wac.sendProto(msgProto)
case ImageMessage:
var err error
m.url, m.mediaKey, m.fileEncSha256, m.fileSha256, m.fileLength, err = wac.Upload(m.Content, MediaImage)
if err != nil {
return "ERROR", fmt.Errorf("image upload failed: %v", err)
}
msgProto = getImageProto(m)
msgInfo = getMessageInfo(msgProto)
ch, err = wac.sendProto(msgProto)
case VideoMessage:
var err error
m.url, m.mediaKey, m.fileEncSha256, m.fileSha256, m.fileLength, err = wac.Upload(m.Content, MediaVideo)
if err != nil {
return "ERROR", fmt.Errorf("video upload failed: %v", err)
}
msgProto = getVideoProto(m)
msgInfo = getMessageInfo(msgProto)
ch, err = wac.sendProto(msgProto)
case DocumentMessage:
var err error
m.url, m.mediaKey, m.fileEncSha256, m.fileSha256, m.fileLength, err = wac.Upload(m.Content, MediaDocument)
if err != nil {
return "ERROR", fmt.Errorf("document upload failed: %v", err)
}
msgProto = getDocumentProto(m)
msgInfo = getMessageInfo(msgProto)
ch, err = wac.sendProto(msgProto)
case AudioMessage:
var err error
m.url, m.mediaKey, m.fileEncSha256, m.fileSha256, m.fileLength, err = wac.Upload(m.Content, MediaAudio)
if err != nil {
return "ERROR", fmt.Errorf("audio upload failed: %v", err)
}
msgProto = getAudioProto(m)
msgInfo = getMessageInfo(msgProto)
ch, err = wac.sendProto(msgProto)
case LocationMessage:
msgProto = GetLocationProto(m)
msgInfo = getMessageInfo(msgProto)
ch, err = wac.sendProto(msgProto)
case LiveLocationMessage:
msgProto = GetLiveLocationProto(m)
msgInfo = getMessageInfo(msgProto)
ch, err = wac.sendProto(msgProto)
case ContactMessage:
msgProto = getContactMessageProto(m)
default:
return "ERROR", fmt.Errorf("cannot match type %T, use message types declared in the package", msg)
}
ch, err := wac.sendProto(msgProto)
if err != nil {
return "ERROR", fmt.Errorf("could not send proto: %v", err)
}
@ -95,7 +84,7 @@ func (wac *Conn) Send(msg interface{}) (string, error) {
return "ERROR", fmt.Errorf("message sending responded with %d", resp["status"])
}
if int(resp["status"].(float64)) == 200 {
return msgInfo.Id, nil
return getMessageInfo(msgProto).Id, nil
}
case <-time.After(wac.msgTimeout):
return "ERROR", fmt.Errorf("sending message timed out")
@ -124,15 +113,13 @@ func init() {
MessageInfo contains general message information. It is part of every of every message type.
*/
type MessageInfo struct {
Id string
RemoteJid string
SenderJid string
FromMe bool
Timestamp uint64
PushName string
Status MessageStatus
QuotedMessageID string
QuotedMessage proto.Message
Id string
RemoteJid string
SenderJid string
FromMe bool
Timestamp uint64
PushName string
Status MessageStatus
Source *proto.WebMessageInfo
}
@ -185,14 +172,35 @@ func getInfoProto(info *MessageInfo) *proto.WebMessageInfo {
}
}
func getContextInfoProto(info *MessageInfo) *proto.ContextInfo {
if len(info.QuotedMessageID) > 0 {
/*
ContextInfo represents contextinfo of every message
*/
type ContextInfo struct {
QuotedMessageID string //StanzaId
QuotedMessage *proto.Message
Participant string
IsForwarded bool
}
func getMessageContext(msg *proto.ContextInfo) ContextInfo {
return ContextInfo{
QuotedMessageID: msg.GetStanzaId(), //StanzaId
QuotedMessage: msg.GetQuotedMessage(),
Participant: msg.GetParticipant(),
IsForwarded: msg.GetIsForwarded(),
}
}
func getContextInfoProto(context *ContextInfo) *proto.ContextInfo {
if len(context.QuotedMessageID) > 0 {
contextInfo := &proto.ContextInfo{
StanzaId: &info.QuotedMessageID,
StanzaId: &context.QuotedMessageID,
}
if &info.QuotedMessage != nil {
contextInfo.QuotedMessage = &info.QuotedMessage
if &context.QuotedMessage != nil {
contextInfo.QuotedMessage = context.QuotedMessage
contextInfo.Participant = &context.Participant
}
return contextInfo
@ -205,24 +213,28 @@ func getContextInfoProto(info *MessageInfo) *proto.ContextInfo {
TextMessage represents a text message.
*/
type TextMessage struct {
Info MessageInfo
Text string
Info MessageInfo
Text string
ContextInfo ContextInfo
}
func getTextMessage(msg *proto.WebMessageInfo) TextMessage {
text := TextMessage{Info: getMessageInfo(msg)}
if m := msg.GetMessage().GetExtendedTextMessage(); m != nil {
text.Text = m.GetText()
text.Info.QuotedMessageID = m.GetContextInfo().GetStanzaId()
text.ContextInfo = getMessageContext(m.GetContextInfo())
} else {
text.Text = msg.GetMessage().GetConversation()
}
return text
}
func getTextProto(msg TextMessage) *proto.WebMessageInfo {
p := getInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.ContextInfo)
if contextInfo == nil {
p.Message = &proto.Message{
@ -255,6 +267,7 @@ type ImageMessage struct {
fileEncSha256 []byte
fileSha256 []byte
fileLength uint64
ContextInfo ContextInfo
}
func getImageMessage(msg *proto.WebMessageInfo) ImageMessage {
@ -270,10 +283,7 @@ func getImageMessage(msg *proto.WebMessageInfo) ImageMessage {
fileEncSha256: image.GetFileEncSha256(),
fileSha256: image.GetFileSha256(),
fileLength: image.GetFileLength(),
}
if contextInfo := image.GetContextInfo(); contextInfo != nil {
imageMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
ContextInfo: getMessageContext(image.GetContextInfo()),
}
return imageMessage
@ -281,7 +291,7 @@ func getImageMessage(msg *proto.WebMessageInfo) ImageMessage {
func getImageProto(msg ImageMessage) *proto.WebMessageInfo {
p := getInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.ContextInfo)
p.Message = &proto.Message{
ImageMessage: &proto.ImageMessage{
@ -323,6 +333,7 @@ type VideoMessage struct {
fileEncSha256 []byte
fileSha256 []byte
fileLength uint64
ContextInfo ContextInfo
}
func getVideoMessage(msg *proto.WebMessageInfo) VideoMessage {
@ -340,10 +351,7 @@ func getVideoMessage(msg *proto.WebMessageInfo) VideoMessage {
fileEncSha256: vid.GetFileEncSha256(),
fileSha256: vid.GetFileSha256(),
fileLength: vid.GetFileLength(),
}
if contextInfo := vid.GetContextInfo(); contextInfo != nil {
videoMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
ContextInfo: getMessageContext(vid.GetContextInfo()),
}
return videoMessage
@ -351,7 +359,7 @@ func getVideoMessage(msg *proto.WebMessageInfo) VideoMessage {
func getVideoProto(msg VideoMessage) *proto.WebMessageInfo {
p := getInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.ContextInfo)
p.Message = &proto.Message{
VideoMessage: &proto.VideoMessage{
@ -393,6 +401,7 @@ type AudioMessage struct {
fileEncSha256 []byte
fileSha256 []byte
fileLength uint64
ContextInfo ContextInfo
}
func getAudioMessage(msg *proto.WebMessageInfo) AudioMessage {
@ -407,10 +416,7 @@ func getAudioMessage(msg *proto.WebMessageInfo) AudioMessage {
fileEncSha256: aud.GetFileEncSha256(),
fileSha256: aud.GetFileSha256(),
fileLength: aud.GetFileLength(),
}
if contextInfo := aud.GetContextInfo(); contextInfo != nil {
audioMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
ContextInfo: getMessageContext(aud.GetContextInfo()),
}
return audioMessage
@ -418,7 +424,7 @@ func getAudioMessage(msg *proto.WebMessageInfo) AudioMessage {
func getAudioProto(msg AudioMessage) *proto.WebMessageInfo {
p := getInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.ContextInfo)
p.Message = &proto.Message{
AudioMessage: &proto.AudioMessage{
Url: &msg.url,
@ -459,6 +465,7 @@ type DocumentMessage struct {
fileEncSha256 []byte
fileSha256 []byte
fileLength uint64
ContextInfo ContextInfo
}
func getDocumentMessage(msg *proto.WebMessageInfo) DocumentMessage {
@ -476,10 +483,7 @@ func getDocumentMessage(msg *proto.WebMessageInfo) DocumentMessage {
fileEncSha256: doc.GetFileEncSha256(),
fileSha256: doc.GetFileSha256(),
fileLength: doc.GetFileLength(),
}
if contextInfo := doc.GetContextInfo(); contextInfo != nil {
documentMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
ContextInfo: getMessageContext(doc.GetContextInfo()),
}
return documentMessage
@ -487,7 +491,7 @@ func getDocumentMessage(msg *proto.WebMessageInfo) DocumentMessage {
func getDocumentProto(msg DocumentMessage) *proto.WebMessageInfo {
p := getInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.ContextInfo)
p.Message = &proto.Message{
DocumentMessage: &proto.DocumentMessage{
JpegThumbnail: msg.Thumbnail,
@ -523,6 +527,7 @@ type LocationMessage struct {
Address string
Url string
JpegThumbnail []byte
ContextInfo ContextInfo
}
func GetLocationMessage(msg *proto.WebMessageInfo) LocationMessage {
@ -536,10 +541,7 @@ func GetLocationMessage(msg *proto.WebMessageInfo) LocationMessage {
Address: loc.GetAddress(),
Url: loc.GetUrl(),
JpegThumbnail: loc.GetJpegThumbnail(),
}
if contextInfo := loc.GetContextInfo(); contextInfo != nil {
locationMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
ContextInfo: getMessageContext(loc.GetContextInfo()),
}
return locationMessage
@ -547,7 +549,7 @@ func GetLocationMessage(msg *proto.WebMessageInfo) LocationMessage {
func GetLocationProto(msg LocationMessage) *proto.WebMessageInfo {
p := getInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.ContextInfo)
p.Message = &proto.Message{
LocationMessage: &proto.LocationMessage{
@ -576,6 +578,7 @@ type LiveLocationMessage struct {
Caption string
SequenceNumber int64
JpegThumbnail []byte
ContextInfo ContextInfo
}
func GetLiveLocationMessage(msg *proto.WebMessageInfo) LiveLocationMessage {
@ -591,10 +594,7 @@ func GetLiveLocationMessage(msg *proto.WebMessageInfo) LiveLocationMessage {
Caption: loc.GetCaption(),
SequenceNumber: loc.GetSequenceNumber(),
JpegThumbnail: loc.GetJpegThumbnail(),
}
if contextInfo := loc.GetContextInfo(); contextInfo != nil {
liveLocationMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
ContextInfo: getMessageContext(loc.GetContextInfo()),
}
return liveLocationMessage
@ -602,7 +602,7 @@ func GetLiveLocationMessage(msg *proto.WebMessageInfo) LiveLocationMessage {
func GetLiveLocationProto(msg LiveLocationMessage) *proto.WebMessageInfo {
p := getInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.ContextInfo)
p.Message = &proto.Message{
LiveLocationMessage: &proto.LiveLocationMessage{
DegreesLatitude: &msg.DegreesLatitude,
@ -625,7 +625,6 @@ StickerMessage represents a sticker message.
type StickerMessage struct {
Info MessageInfo
Thumbnail []byte
Type string
Content io.Reader
url string
@ -633,30 +632,79 @@ type StickerMessage struct {
fileEncSha256 []byte
fileSha256 []byte
fileLength uint64
ContextInfo ContextInfo
}
func getStickerMessage(msg *proto.WebMessageInfo) StickerMessage {
sticker := msg.GetMessage().GetStickerMessage()
StickerMessage := StickerMessage{
stickerMessage := StickerMessage{
Info: getMessageInfo(msg),
Thumbnail: sticker.GetPngThumbnail(),
url: sticker.GetUrl(),
mediaKey: sticker.GetMediaKey(),
Type: sticker.GetMimetype(),
fileEncSha256: sticker.GetFileEncSha256(),
fileSha256: sticker.GetFileSha256(),
fileLength: sticker.GetFileLength(),
ContextInfo: getMessageContext(sticker.GetContextInfo()),
}
if contextInfo := sticker.GetContextInfo(); contextInfo != nil {
StickerMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
return stickerMessage
}
/*
Download is the function to retrieve Sticker media data. The media gets downloaded, validated and returned.
*/
func (m *StickerMessage) Download() ([]byte, error) {
return Download(m.url, m.mediaKey, MediaImage, int(m.fileLength))
}
/*
ContactMessage represents a contact message.
*/
type ContactMessage struct {
Info MessageInfo
DisplayName string
Vcard string
ContextInfo ContextInfo
}
func getContactMessage(msg *proto.WebMessageInfo) ContactMessage {
contact := msg.GetMessage().GetContactMessage()
contactMessage := ContactMessage{
Info: getMessageInfo(msg),
DisplayName: contact.GetDisplayName(),
Vcard: contact.GetVcard(),
ContextInfo: getMessageContext(contact.GetContextInfo()),
}
return StickerMessage
return contactMessage
}
func getContactMessageProto(msg ContactMessage) *proto.WebMessageInfo {
p := getInfoProto(&msg.Info)
contextInfo := getContextInfoProto(&msg.ContextInfo)
p.Message = &proto.Message{
ContactMessage: &proto.ContactMessage{
DisplayName: &msg.DisplayName,
Vcard: &msg.Vcard,
ContextInfo: contextInfo,
},
}
return p
}
func ParseProtoMessage(msg *proto.WebMessageInfo) interface{} {
switch {
case msg.GetMessage().GetAudioMessage() != nil:
@ -686,8 +734,12 @@ func ParseProtoMessage(msg *proto.WebMessageInfo) interface{} {
case msg.GetMessage().GetStickerMessage() != nil:
return getStickerMessage(msg)
case msg.GetMessage().GetContactMessage() != nil:
return getContactMessage(msg)
default:
//cannot match message
}
return nil

43
vendor/github.com/Rhymen/go-whatsapp/profile.go generated vendored Normal file
View File

@ -0,0 +1,43 @@
package whatsapp
import (
"fmt"
"github.com/Rhymen/go-whatsapp/binary"
"strconv"
"time"
)
// Pictures must be JPG 640x640 and 96x96, respectively
func (wac *Conn) UploadProfilePic(image, preview []byte) (<-chan string, error) {
tag := fmt.Sprintf("%d.--%d", time.Now().Unix(), wac.msgCount*19)
n := binary.Node{
Description: "action",
Attributes: map[string]string{
"type": "set",
"epoch": strconv.Itoa(wac.msgCount),
},
Content: []interface{}{
binary.Node{
Description: "picture",
Attributes: map[string]string{
"id": tag,
"jid": wac.Info.Wid,
"type": "set",
},
Content: []binary.Node{
{
Description: "image",
Attributes: nil,
Content: image,
},
{
Description: "preview",
Attributes: nil,
Content: preview,
},
},
},
},
}
return wac.writeBinary(n, profile, 136, tag)
}

View File

@ -5,16 +5,22 @@ import (
"crypto/sha256"
"encoding/json"
"fmt"
"strconv"
"time"
"github.com/Rhymen/go-whatsapp/binary"
"github.com/Rhymen/go-whatsapp/crypto/cbc"
"github.com/gorilla/websocket"
"github.com/pkg/errors"
"strconv"
"time"
)
//writeJson enqueues a json message into the writeChan
func (wac *Conn) writeJson(data []interface{}) (<-chan string, error) {
wac.writerLock.Lock()
defer wac.writerLock.Unlock()
d, err := json.Marshal(data)
if err != nil {
return nil, err
@ -38,6 +44,9 @@ func (wac *Conn) writeBinary(node binary.Node, metric metric, flag flag, message
return nil, ErrMissingMessageTag
}
wac.writerLock.Lock()
defer wac.writerLock.Unlock()
data, err := wac.encryptBinaryMessage(node)
if err != nil {
return nil, errors.Wrap(err, "encryptBinaryMessage(node) failed")