diff --git a/whatsapp-ext/conn.go b/whatsapp-ext/conn.go
new file mode 100644
index 0000000..37c5192
--- /dev/null
+++ b/whatsapp-ext/conn.go
@@ -0,0 +1,59 @@
+// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
+// Copyright (C) 2018 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 .
+
+package whatsapp_ext
+
+import (
+ "github.com/Rhymen/go-whatsapp"
+ "encoding/json"
+)
+
+type ConnInfo struct {
+ ProtocolVersion []int `json:"protoVersion"`
+ BinaryVersion int `json:"binVersion"`
+ Phone struct {
+ WhatsAppVersion string `json:"wa_version"`
+ MCC int `json:"mcc"`
+ MNC int `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
+ }
+ connInfoHandler.HandleConnInfo(event)
+ }
+}
diff --git a/whatsapp-ext/jsonmessage.go b/whatsapp-ext/jsonmessage.go
new file mode 100644
index 0000000..be44375
--- /dev/null
+++ b/whatsapp-ext/jsonmessage.go
@@ -0,0 +1,93 @@
+// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
+// Copyright (C) 2018 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 .
+
+package whatsapp_ext
+
+import (
+ "encoding/json"
+ "github.com/Rhymen/go-whatsapp"
+)
+
+type JSONMessage []json.RawMessage
+
+type JSONMessageType string
+
+const (
+ MessageMsgInfo JSONMessageType = "MsgInfo"
+ MessagePresence JSONMessageType = "Presence"
+ MessageStream JSONMessageType = "Stream"
+ MessageConn JSONMessageType = "Conn"
+ MessageProps JSONMessageType = "Props"
+)
+
+func (ext *ExtendedConn) AddHandler(handler whatsapp.Handler) {
+ ext.Conn.AddHandler(handler)
+ ext.handlers = append(ext.handlers, handler)
+}
+
+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 {
+ 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.handleMessageProps(msg[1])
+ case MessageProps:
+ ext.handleMessageProps(msg[1])
+ case MessageMsgInfo:
+ ext.handleMessageMsgInfo(msg[1])
+ default:
+ for _, handler := range ext.handlers {
+ ujmHandler, ok := handler.(UnhandledJSONMessageHandler)
+ if !ok {
+ continue
+ }
+ ujmHandler.HandleUnhandledJSONMessage(message)
+ }
+ }
+}
diff --git a/whatsapp-ext/msginfo.go b/whatsapp-ext/msginfo.go
new file mode 100644
index 0000000..f63f454
--- /dev/null
+++ b/whatsapp-ext/msginfo.go
@@ -0,0 +1,63 @@
+// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
+// Copyright (C) 2018 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 .
+
+package whatsapp_ext
+
+import (
+ "github.com/Rhymen/go-whatsapp"
+ "encoding/json"
+ "strings"
+)
+
+type MsgInfoCommand string
+
+const (
+ MsgInfoCommandAcknowledge MsgInfoCommand = "ack"
+)
+
+type MsgInfo struct {
+ Command MsgInfoCommand `json:"cmd"`
+ ID string `json:"id"`
+ Acknowledgement int `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(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)
+ for _, handler := range ext.handlers {
+ msgInfoHandler, ok := handler.(MsgInfoHandler)
+ if !ok {
+ continue
+ }
+ msgInfoHandler.HandleMsgInfo(event)
+ }
+}
diff --git a/whatsapp-ext/presence.go b/whatsapp-ext/presence.go
new file mode 100644
index 0000000..57a6507
--- /dev/null
+++ b/whatsapp-ext/presence.go
@@ -0,0 +1,58 @@
+// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
+// Copyright (C) 2018 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 .
+
+package whatsapp_ext
+
+import (
+ "github.com/Rhymen/go-whatsapp"
+ "encoding/json"
+ "strings"
+)
+
+type PresenceType string
+
+const (
+ PresenceUnavailable PresenceType = "unavailable"
+ PresenceAvailable PresenceType = "available"
+)
+
+type Presence struct {
+ JID string `json:"id"`
+ Status PresenceType `json:"type"`
+ Timestamp int64 `json:"t"`
+}
+
+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)
+ for _, handler := range ext.handlers {
+ presenceHandler, ok := handler.(PresenceHandler)
+ if !ok {
+ continue
+ }
+ presenceHandler.HandlePresence(event)
+ }
+}
diff --git a/whatsapp-ext/props.go b/whatsapp-ext/props.go
new file mode 100644
index 0000000..ecf847a
--- /dev/null
+++ b/whatsapp-ext/props.go
@@ -0,0 +1,67 @@
+// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
+// Copyright (C) 2018 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 .
+
+package whatsapp_ext
+
+import (
+ "github.com/Rhymen/go-whatsapp"
+ "encoding/json"
+)
+
+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
+ }
+ protocolPropsHandler.HandleProtocolProps(event)
+ }
+}
diff --git a/whatsapp-ext/stream.go b/whatsapp-ext/stream.go
new file mode 100644
index 0000000..5496df7
--- /dev/null
+++ b/whatsapp-ext/stream.go
@@ -0,0 +1,62 @@
+// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
+// Copyright (C) 2018 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 .
+
+package whatsapp_ext
+
+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
+ }
+ streamHandler.HandleStreamEvent(event)
+ }
+}
diff --git a/whatsapp-ext/whatsapp.go b/whatsapp-ext/whatsapp.go
index 4941c64..649c1a7 100644
--- a/whatsapp-ext/whatsapp.go
+++ b/whatsapp-ext/whatsapp.go
@@ -26,14 +26,23 @@ import (
"strings"
)
+const (
+ OldUserSuffix = "@c.us"
+ NewUserSuffix = "@s.whatsapp.net"
+)
+
type ExtendedConn struct {
*whatsapp.Conn
+
+ handlers []whatsapp.Handler
}
func ExtendConn(conn *whatsapp.Conn) *ExtendedConn {
- return &ExtendedConn{
+ ext := &ExtendedConn{
Conn: conn,
}
+ ext.Conn.AddHandler(ext)
+ return ext
}
type GroupInfo struct {
@@ -64,7 +73,7 @@ func (ext *ExtendedConn) GetGroupMetaData(jid string) (*GroupInfo, error) {
return nil, fmt.Errorf("failed to get group metadata: %v", err)
}
content := <-data
- fmt.Println("GROUP METADATA", content)
+
info := &GroupInfo{}
err = json.Unmarshal([]byte(content), info)
if err != nil {
@@ -72,7 +81,7 @@ func (ext *ExtendedConn) GetGroupMetaData(jid string) (*GroupInfo, error) {
}
for index, participant := range info.Participants {
- info.Participants[index].JID = strings.Replace(participant.JID, "@c.us", "@s.whatsapp.net", 1)
+ info.Participants[index].JID = strings.Replace(participant.JID, OldUserSuffix, NewUserSuffix, 1)
}
return info, nil