Move whatsapp-ext to go-whatsapp
This commit is contained in:
parent
ebf2072025
commit
69dd7f803a
40 changed files with 203 additions and 1732 deletions
11
commands.go
11
commands.go
|
@ -35,7 +35,6 @@ import (
|
|||
"maunium.net/go/mautrix/id"
|
||||
|
||||
"maunium.net/go/mautrix-whatsapp/database"
|
||||
"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
|
||||
)
|
||||
|
||||
type CommandHandler struct {
|
||||
|
@ -737,12 +736,12 @@ const cmdListHelp = `list <contacts|groups> [page] [items per page] - Get a list
|
|||
|
||||
func formatContacts(contacts bool, input map[string]whatsapp.Contact) (result []string) {
|
||||
for jid, contact := range input {
|
||||
if strings.HasSuffix(jid, whatsappExt.NewUserSuffix) != contacts {
|
||||
if strings.HasSuffix(jid, whatsapp.NewUserSuffix) != contacts {
|
||||
continue
|
||||
}
|
||||
|
||||
if contacts {
|
||||
result = append(result, fmt.Sprintf("* %s / %s - `%s`", contact.Name, contact.Notify, contact.Jid[:len(contact.Jid)-len(whatsappExt.NewUserSuffix)]))
|
||||
result = append(result, fmt.Sprintf("* %s / %s - `%s`", contact.Name, contact.Notify, contact.Jid[:len(contact.Jid)-len(whatsapp.NewUserSuffix)]))
|
||||
} else {
|
||||
result = append(result, fmt.Sprintf("* %s - `%s`", contact.Name, contact.Jid))
|
||||
}
|
||||
|
@ -818,8 +817,8 @@ func (handler *CommandHandler) CommandOpen(ce *CommandEvent) {
|
|||
user := ce.User
|
||||
jid := ce.Args[0]
|
||||
|
||||
if strings.HasSuffix(jid, whatsappExt.NewUserSuffix) {
|
||||
ce.Reply("That looks like a user JID. Did you mean `pm %s`?", jid[:len(jid)-len(whatsappExt.NewUserSuffix)])
|
||||
if strings.HasSuffix(jid, whatsapp.NewUserSuffix) {
|
||||
ce.Reply("That looks like a user JID. Did you mean `pm %s`?", jid[:len(jid)-len(whatsapp.NewUserSuffix)])
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -865,7 +864,7 @@ func (handler *CommandHandler) CommandPM(ce *CommandEvent) {
|
|||
return
|
||||
}
|
||||
}
|
||||
jid := number + whatsappExt.NewUserSuffix
|
||||
jid := number + whatsapp.NewUserSuffix
|
||||
|
||||
handler.log.Debugln("Importing", jid, "for", user)
|
||||
|
||||
|
|
|
@ -26,8 +26,6 @@ import (
|
|||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
|
||||
"maunium.net/go/mautrix-whatsapp/types"
|
||||
)
|
||||
|
||||
type BridgeConfig struct {
|
||||
|
@ -185,7 +183,7 @@ func (bc BridgeConfig) FormatDisplayname(contact whatsapp.Contact) (string, int8
|
|||
return buf.String(), quality
|
||||
}
|
||||
|
||||
func (bc BridgeConfig) FormatUsername(userID types.WhatsAppID) string {
|
||||
func (bc BridgeConfig) FormatUsername(userID whatsapp.JID) string {
|
||||
var buf bytes.Buffer
|
||||
bc.usernameTemplate.Execute(&buf, userID)
|
||||
return buf.String()
|
||||
|
|
|
@ -22,11 +22,11 @@ import (
|
|||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/Rhymen/go-whatsapp"
|
||||
waProto "github.com/Rhymen/go-whatsapp/binary/proto"
|
||||
|
||||
log "maunium.net/go/maulogger/v2"
|
||||
|
||||
"maunium.net/go/mautrix-whatsapp/types"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
|
@ -54,18 +54,18 @@ func (mq *MessageQuery) GetAll(chat PortalKey) (messages []*Message) {
|
|||
return
|
||||
}
|
||||
|
||||
func (mq *MessageQuery) GetByJID(chat PortalKey, jid types.WhatsAppMessageID) *Message {
|
||||
return mq.get("SELECT chat_jid, chat_receiver, jid, mxid, sender, timestamp, content " +
|
||||
func (mq *MessageQuery) GetByJID(chat PortalKey, jid whatsapp.MessageID) *Message {
|
||||
return mq.get("SELECT chat_jid, chat_receiver, jid, mxid, sender, timestamp, content "+
|
||||
"FROM message WHERE chat_jid=$1 AND chat_receiver=$2 AND jid=$3", chat.JID, chat.Receiver, jid)
|
||||
}
|
||||
|
||||
func (mq *MessageQuery) GetByMXID(mxid id.EventID) *Message {
|
||||
return mq.get("SELECT chat_jid, chat_receiver, jid, mxid, sender, timestamp, content " +
|
||||
return mq.get("SELECT chat_jid, chat_receiver, jid, mxid, sender, timestamp, content "+
|
||||
"FROM message WHERE mxid=$1", mxid)
|
||||
}
|
||||
|
||||
func (mq *MessageQuery) GetLastInChat(chat PortalKey) *Message {
|
||||
msg := mq.get("SELECT chat_jid, chat_receiver, jid, mxid, sender, timestamp, content " +
|
||||
msg := mq.get("SELECT chat_jid, chat_receiver, jid, mxid, sender, timestamp, content "+
|
||||
"FROM message WHERE chat_jid=$1 AND chat_receiver=$2 ORDER BY timestamp DESC LIMIT 1", chat.JID, chat.Receiver)
|
||||
if msg == nil || msg.Timestamp == 0 {
|
||||
// Old db, we don't know what the last message is.
|
||||
|
@ -87,9 +87,9 @@ type Message struct {
|
|||
log log.Logger
|
||||
|
||||
Chat PortalKey
|
||||
JID types.WhatsAppMessageID
|
||||
JID whatsapp.MessageID
|
||||
MXID id.EventID
|
||||
Sender types.WhatsAppID
|
||||
Sender whatsapp.JID
|
||||
Timestamp uint64
|
||||
Content *waProto.Message
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ func (msg *Message) encodeBinaryContent() []byte {
|
|||
}
|
||||
|
||||
func (msg *Message) Insert() {
|
||||
_, err := msg.db.Exec("INSERT INTO message (chat_jid, chat_receiver, jid, mxid, sender, timestamp, content) " +
|
||||
_, err := msg.db.Exec("INSERT INTO message (chat_jid, chat_receiver, jid, mxid, sender, timestamp, content) "+
|
||||
"VALUES ($1, $2, $3, $4, $5, $6, $7)",
|
||||
msg.Chat.JID, msg.Chat.Receiver, msg.JID, msg.MXID, msg.Sender, msg.Timestamp, msg.encodeBinaryContent())
|
||||
if err != nil {
|
||||
|
|
|
@ -22,24 +22,24 @@ import (
|
|||
|
||||
log "maunium.net/go/maulogger/v2"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
"github.com/Rhymen/go-whatsapp"
|
||||
|
||||
"maunium.net/go/mautrix-whatsapp/types"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type PortalKey struct {
|
||||
JID types.WhatsAppID
|
||||
Receiver types.WhatsAppID
|
||||
JID whatsapp.JID
|
||||
Receiver whatsapp.JID
|
||||
}
|
||||
|
||||
func GroupPortalKey(jid types.WhatsAppID) PortalKey {
|
||||
func GroupPortalKey(jid whatsapp.JID) PortalKey {
|
||||
return PortalKey{
|
||||
JID: jid,
|
||||
Receiver: jid,
|
||||
}
|
||||
}
|
||||
|
||||
func NewPortalKey(jid, receiver types.WhatsAppID) PortalKey {
|
||||
func NewPortalKey(jid, receiver whatsapp.JID) PortalKey {
|
||||
if strings.HasSuffix(jid, "@g.us") {
|
||||
receiver = jid
|
||||
}
|
||||
|
@ -80,11 +80,11 @@ func (pq *PortalQuery) GetByMXID(mxid id.RoomID) *Portal {
|
|||
return pq.get("SELECT * FROM portal WHERE mxid=$1", mxid)
|
||||
}
|
||||
|
||||
func (pq *PortalQuery) GetAllByJID(jid types.WhatsAppID) []*Portal {
|
||||
func (pq *PortalQuery) GetAllByJID(jid whatsapp.JID) []*Portal {
|
||||
return pq.getAll("SELECT * FROM portal WHERE jid=$1", jid)
|
||||
}
|
||||
|
||||
func (pq *PortalQuery) FindPrivateChats(receiver types.WhatsAppID) []*Portal {
|
||||
func (pq *PortalQuery) FindPrivateChats(receiver whatsapp.JID) []*Portal {
|
||||
return pq.getAll("SELECT * FROM portal WHERE receiver=$1 AND jid LIKE '%@s.whatsapp.net'", receiver)
|
||||
}
|
||||
|
||||
|
|
|
@ -21,9 +21,9 @@ import (
|
|||
|
||||
log "maunium.net/go/maulogger/v2"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
"github.com/Rhymen/go-whatsapp"
|
||||
|
||||
"maunium.net/go/mautrix-whatsapp/types"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type PuppetQuery struct {
|
||||
|
@ -53,7 +53,7 @@ func (pq *PuppetQuery) GetAll() (puppets []*Puppet) {
|
|||
return
|
||||
}
|
||||
|
||||
func (pq *PuppetQuery) Get(jid types.WhatsAppID) *Puppet {
|
||||
func (pq *PuppetQuery) Get(jid whatsapp.JID) *Puppet {
|
||||
row := pq.db.QueryRow("SELECT jid, avatar, avatar_url, displayname, name_quality, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet WHERE jid=$1", jid)
|
||||
if row == nil {
|
||||
return nil
|
||||
|
@ -85,7 +85,7 @@ type Puppet struct {
|
|||
db *Database
|
||||
log log.Logger
|
||||
|
||||
JID types.WhatsAppID
|
||||
JID whatsapp.JID
|
||||
Avatar string
|
||||
AvatarURL id.ContentURI
|
||||
Displayname string
|
||||
|
|
|
@ -26,8 +26,6 @@ import (
|
|||
|
||||
log "maunium.net/go/maulogger/v2"
|
||||
|
||||
"maunium.net/go/mautrix-whatsapp/types"
|
||||
"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
|
@ -63,7 +61,7 @@ func (uq *UserQuery) GetByMXID(userID id.UserID) *User {
|
|||
return uq.New().Scan(row)
|
||||
}
|
||||
|
||||
func (uq *UserQuery) GetByJID(userID types.WhatsAppID) *User {
|
||||
func (uq *UserQuery) GetByJID(userID whatsapp.JID) *User {
|
||||
row := uq.db.QueryRow(`SELECT mxid, jid, management_room, last_connection, client_id, client_token, server_token, enc_key, mac_key FROM "user" WHERE jid=$1`, stripSuffix(userID))
|
||||
if row == nil {
|
||||
return nil
|
||||
|
@ -76,7 +74,7 @@ type User struct {
|
|||
log log.Logger
|
||||
|
||||
MXID id.UserID
|
||||
JID types.WhatsAppID
|
||||
JID whatsapp.JID
|
||||
ManagementRoom id.RoomID
|
||||
Session *whatsapp.Session
|
||||
LastConnection uint64
|
||||
|
@ -93,14 +91,14 @@ func (user *User) Scan(row Scannable) *User {
|
|||
return nil
|
||||
}
|
||||
if len(jid.String) > 0 && len(clientID.String) > 0 {
|
||||
user.JID = jid.String + whatsappExt.NewUserSuffix
|
||||
user.JID = jid.String + whatsapp.NewUserSuffix
|
||||
user.Session = &whatsapp.Session{
|
||||
ClientId: clientID.String,
|
||||
ClientToken: clientToken.String,
|
||||
ServerToken: serverToken.String,
|
||||
EncKey: encKey,
|
||||
MacKey: macKey,
|
||||
Wid: jid.String + whatsappExt.OldUserSuffix,
|
||||
Wid: jid.String + whatsapp.OldUserSuffix,
|
||||
}
|
||||
} else {
|
||||
user.Session = nil
|
||||
|
@ -108,7 +106,7 @@ func (user *User) Scan(row Scannable) *User {
|
|||
return user
|
||||
}
|
||||
|
||||
func stripSuffix(jid types.WhatsAppID) string {
|
||||
func stripSuffix(jid whatsapp.JID) string {
|
||||
if len(jid) == 0 {
|
||||
return jid
|
||||
}
|
||||
|
|
|
@ -22,12 +22,11 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Rhymen/go-whatsapp"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/format"
|
||||
"maunium.net/go/mautrix/id"
|
||||
|
||||
"maunium.net/go/mautrix-whatsapp/types"
|
||||
"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
|
||||
)
|
||||
|
||||
var italicRegex = regexp.MustCompile("([\\s>~*]|^)_(.+?)_([^a-zA-Z\\d]|$)")
|
||||
|
@ -58,9 +57,9 @@ func NewFormatter(bridge *Bridge) *Formatter {
|
|||
if mxid[0] == '@' {
|
||||
puppet := bridge.GetPuppetByMXID(id.UserID(mxid))
|
||||
if puppet != nil {
|
||||
jids, ok := ctx[mentionedJIDsContextKey].([]types.WhatsAppID)
|
||||
jids, ok := ctx[mentionedJIDsContextKey].([]whatsapp.JID)
|
||||
if !ok {
|
||||
ctx[mentionedJIDsContextKey] = []types.WhatsAppID{puppet.JID}
|
||||
ctx[mentionedJIDsContextKey] = []whatsapp.JID{puppet.JID}
|
||||
} else {
|
||||
ctx[mentionedJIDsContextKey] = append(jids, puppet.JID)
|
||||
}
|
||||
|
@ -105,7 +104,7 @@ func NewFormatter(bridge *Bridge) *Formatter {
|
|||
return formatter
|
||||
}
|
||||
|
||||
func (formatter *Formatter) getMatrixInfoByJID(jid types.WhatsAppID) (mxid id.UserID, displayname string) {
|
||||
func (formatter *Formatter) getMatrixInfoByJID(jid whatsapp.JID) (mxid id.UserID, displayname string) {
|
||||
if user := formatter.bridge.GetUserByJID(jid); user != nil {
|
||||
mxid = user.MXID
|
||||
displayname = string(user.MXID)
|
||||
|
@ -116,7 +115,7 @@ func (formatter *Formatter) getMatrixInfoByJID(jid types.WhatsAppID) (mxid id.Us
|
|||
return
|
||||
}
|
||||
|
||||
func (formatter *Formatter) ParseWhatsApp(content *event.MessageEventContent, mentionedJIDs []types.WhatsAppID) {
|
||||
func (formatter *Formatter) ParseWhatsApp(content *event.MessageEventContent, mentionedJIDs []whatsapp.JID) {
|
||||
output := html.EscapeString(content.Body)
|
||||
for regex, replacement := range formatter.waReplString {
|
||||
output = regex.ReplaceAllString(output, replacement)
|
||||
|
@ -126,7 +125,7 @@ func (formatter *Formatter) ParseWhatsApp(content *event.MessageEventContent, me
|
|||
}
|
||||
for _, jid := range mentionedJIDs {
|
||||
mxid, displayname := formatter.getMatrixInfoByJID(jid)
|
||||
number := "@" + strings.Replace(jid, whatsappExt.NewUserSuffix, "", 1)
|
||||
number := "@" + strings.Replace(jid, whatsapp.NewUserSuffix, "", 1)
|
||||
output = strings.Replace(output, number, fmt.Sprintf(`<a href="https://matrix.to/#/%s">%s</a>`, mxid, displayname), -1)
|
||||
content.Body = strings.Replace(content.Body, number, displayname, -1)
|
||||
}
|
||||
|
@ -140,9 +139,9 @@ func (formatter *Formatter) ParseWhatsApp(content *event.MessageEventContent, me
|
|||
}
|
||||
}
|
||||
|
||||
func (formatter *Formatter) ParseMatrix(html string) (string, []types.WhatsAppID) {
|
||||
func (formatter *Formatter) ParseMatrix(html string) (string, []whatsapp.JID) {
|
||||
ctx := make(format.Context)
|
||||
result := formatter.matrixHTMLParser.Parse(html, ctx)
|
||||
mentionedJIDs, _ := ctx[mentionedJIDsContextKey].([]types.WhatsAppID)
|
||||
mentionedJIDs, _ := ctx[mentionedJIDsContextKey].([]whatsapp.JID)
|
||||
return result, mentionedJIDs
|
||||
}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[*.{yaml,yml}]
|
||||
indent_size = 2
|
2
helm/mautrix-whatsapp/.gitignore
vendored
2
helm/mautrix-whatsapp/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
charts/*
|
||||
!*.yaml
|
|
@ -1,22 +0,0 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
|
@ -1,14 +0,0 @@
|
|||
apiVersion: v1
|
||||
name: mautrix-whatsapp
|
||||
version: 0.1.0
|
||||
appVersion: "0.1.0"
|
||||
description: A Matrix-Whatsapp puppeting bridge.
|
||||
keywords:
|
||||
- matrix
|
||||
- bridge
|
||||
- whatsapp
|
||||
maintainers:
|
||||
- name: Tulir Asokan
|
||||
email: tulir@maunium.net
|
||||
sources:
|
||||
- https://github.com/tulir/mautrix-whatsapp
|
|
@ -1,6 +0,0 @@
|
|||
dependencies:
|
||||
- name: postgresql
|
||||
repository: https://kubernetes-charts.storage.googleapis.com/
|
||||
version: 6.5.0
|
||||
digest: sha256:85139e9d4207e49c11c5f84d7920d0135cffd3d427f3f3638d4e51258990de2a
|
||||
generated: "2019-10-23T22:11:37.005827507+03:00"
|
|
@ -1,5 +0,0 @@
|
|||
dependencies:
|
||||
- name: postgresql
|
||||
version: 6.5.0
|
||||
repository: https://kubernetes-charts.storage.googleapis.com/
|
||||
condition: postgresql.enabled
|
|
@ -1,12 +0,0 @@
|
|||
Your registration file is below. Save it into a YAML file and give the path to that file to synapse:
|
||||
|
||||
id: {{ .Values.appservice.id }}
|
||||
as_token: {{ .Values.appservice.asToken }}
|
||||
hs_token: {{ .Values.appservice.hsToken }}
|
||||
namespaces:
|
||||
users:
|
||||
- exclusive: true
|
||||
regex: "@{{ .Values.bridge.username_template | replace "{{.}}" ".+"}}:{{ .Values.homeserver.domain }}"
|
||||
url: {{ .Values.appservice.address }}
|
||||
sender_localpart: {{ .Values.appservice.botUsername }}
|
||||
rate_limited: false
|
|
@ -1,55 +0,0 @@
|
|||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "mautrix-whatsapp.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "mautrix-whatsapp.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "mautrix-whatsapp.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "mautrix-whatsapp.labels" -}}
|
||||
app.kubernetes.io/name: {{ include "mautrix-whatsapp.name" . }}
|
||||
helm.sh/chart: {{ include "mautrix-whatsapp.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "mautrix-whatsapp.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
{{ default (include "mautrix-whatsapp.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else -}}
|
||||
{{ default "default" .Values.serviceAccount.name }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
|
@ -1,45 +0,0 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ template "mautrix-whatsapp.fullname" . }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||
app.kubernetes.io/name: {{ template "mautrix-whatsapp.name" . }}
|
||||
data:
|
||||
config.yaml: |
|
||||
homeserver:
|
||||
address: {{ .Values.homeserver.address }}
|
||||
domain: {{ .Values.homeserver.domain }}
|
||||
|
||||
appservice:
|
||||
address: http://{{ include "mautrix-whatsapp.fullname" . }}:{{ .Values.service.port }}
|
||||
|
||||
hostname: 0.0.0.0
|
||||
port: {{ .Values.service.port }}
|
||||
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
database:
|
||||
type: postgres
|
||||
uri: "postgres://postgres:{{ .Values.postgresql.postgresqlPassword }}@{{ .Release.Name }}-postgresql/{{ .Values.postgresql.postgresqlDatabase }}?sslmode=disable"
|
||||
{{- else }}
|
||||
database:
|
||||
{{- toYaml .Values.appservice.database | nindent 8 }}
|
||||
{{- end }}
|
||||
|
||||
id: {{ .Values.appservice.id }}
|
||||
bot:
|
||||
username: {{ .Values.appservice.botUsername }}
|
||||
displayname: {{ .Values.appservice.botDisplayname }}
|
||||
avatar: {{ .Values.appservice.botAvatar }}
|
||||
|
||||
as_token: {{ .Values.appservice.asToken }}
|
||||
hs_token: {{ .Values.appservice.hsToken }}
|
||||
|
||||
bridge:
|
||||
{{- toYaml .Values.bridge | nindent 6 }}
|
||||
|
||||
logging:
|
||||
{{- toYaml .Values.logging | nindent 6 }}
|
||||
registration.yaml: ""
|
|
@ -1,69 +0,0 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "mautrix-whatsapp.fullname" . }}
|
||||
labels:
|
||||
{{- include "mautrix-whatsapp.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "mautrix-whatsapp.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
template:
|
||||
{{- if .Values.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml .Values.podAnnotations | nindent 6 }}
|
||||
{{- end }}
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "mautrix-whatsapp.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
serviceAccountName: {{ template "mautrix-whatsapp.serviceAccountName" . }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
volumeMounts:
|
||||
- mountPath: /data
|
||||
name: config-volume
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.port }}
|
||||
protocol: TCP
|
||||
# livenessProbe:
|
||||
# httpGet:
|
||||
# path: /_matrix/mau/live
|
||||
# port: http
|
||||
# initialDelaySeconds: 60
|
||||
# periodSeconds: 5
|
||||
# readinessProbe:
|
||||
# httpGet:
|
||||
# path: /_matrix/mau/ready
|
||||
# port: http
|
||||
# initialDelaySeconds: 60
|
||||
# periodSeconds: 5
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
volumes:
|
||||
- name: config-volume
|
||||
configMap:
|
||||
name: {{ template "mautrix-whatsapp.fullname" . }}
|
||||
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
|
@ -1,16 +0,0 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "mautrix-whatsapp.fullname" . }}
|
||||
labels:
|
||||
{{ include "mautrix-whatsapp.labels" . | indent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ include "mautrix-whatsapp.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
@ -1,8 +0,0 @@
|
|||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ template "mautrix-whatsapp.serviceAccountName" . }}
|
||||
labels:
|
||||
{{ include "mautrix-whatsapp.labels" . | indent 4 }}
|
||||
{{- end -}}
|
|
@ -1,137 +0,0 @@
|
|||
image:
|
||||
repository: dock.mau.dev/tulir/mautrix-whatsapp
|
||||
tag: latest
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: true
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name:
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 29318
|
||||
|
||||
resources: {}
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
|
||||
# Postgres pod configs
|
||||
postgresql:
|
||||
enabled: true
|
||||
postgresqlDatabase: mxwa
|
||||
postgresqlPassword: SET TO RANDOM STRING
|
||||
persistence:
|
||||
size: 2Gi
|
||||
resources:
|
||||
requests:
|
||||
memory: 256Mi
|
||||
cpu: 100m
|
||||
|
||||
# Homeserver details
|
||||
homeserver:
|
||||
# The address that this appservice can use to connect to the homeserver.
|
||||
address: https://example.com
|
||||
# The domain of the homeserver (for MXIDs, etc).
|
||||
domain: example.com
|
||||
|
||||
# Application service host/registration related details
|
||||
# Changing these values requires regeneration of the registration.
|
||||
appservice:
|
||||
id: whatsapp
|
||||
botUsername: whatsappbot
|
||||
# Display name and avatar for bot. Set to "remove" to remove display name/avatar, leave empty
|
||||
# to leave display name/avatar as-is.
|
||||
botDisplayname: WhatsApp bridge bot
|
||||
botAvatar: mxc://maunium.net/NeXNQarUbrlYBiPCpprYsRqr
|
||||
|
||||
# Authentication tokens for AS <-> HS communication.
|
||||
asToken: SET TO RANDOM STRING
|
||||
hsToken: SET TO RANDOM STRING
|
||||
|
||||
# The keys below can be used to override the configs in the base config:
|
||||
# https://github.com/tulir/mautrix-whatsapp/blob/master/example-config.yaml
|
||||
# Note that the "appservice" and "homeserver" sections are above and slightly different than the base.
|
||||
|
||||
# Bridge config
|
||||
bridge:
|
||||
# Localpart template of MXIDs for WhatsApp users.
|
||||
# {{.}} is replaced with the phone number of the WhatsApp user.
|
||||
username_template: whatsapp_{{.}}
|
||||
|
||||
# Number of chats to sync for new users.
|
||||
initial_chat_sync_count: 10
|
||||
# Number of old messages to fill when creating new portal rooms.
|
||||
initial_history_fill_count: 20
|
||||
# Maximum number of chats to sync when recovering from downtime.
|
||||
# Set to -1 to sync all new chats during downtime.
|
||||
recovery_chat_sync_limit: -1
|
||||
# Whether or not to sync history when recovering from downtime.
|
||||
recovery_history_backfill: true
|
||||
# Maximum number of seconds since last message in chat to skip
|
||||
# syncing the chat in any case. This setting will take priority
|
||||
# over both recovery_chat_sync_limit and initial_chat_sync_count.
|
||||
# Default is 3 days = 259200 seconds
|
||||
sync_max_chat_age: 259200
|
||||
|
||||
# Whether or not to explicitly set the avatar and room name for private
|
||||
# chat portal rooms. This can be useful if the previous field works fine,
|
||||
# but causes room avatar/name bugs.
|
||||
private_chat_portal_meta: true
|
||||
|
||||
# Allow invite permission for user. User can invite any bots to room with whatsapp
|
||||
# users (private chat and groups)
|
||||
allow_user_invite: true
|
||||
|
||||
# Permissions for using the bridge.
|
||||
# Permitted values:
|
||||
# relaybot - Talk through the relaybot (if enabled), no access otherwise
|
||||
# user - Access to use the bridge to chat with a WhatsApp account.
|
||||
# admin - User level and some additional administration tools
|
||||
# Permitted keys:
|
||||
# * - All Matrix users
|
||||
# domain - All users on that homeserver
|
||||
# mxid - Specific user
|
||||
permissions:
|
||||
"*": relaybot
|
||||
"example.com": user
|
||||
"@admin:example.com": admin
|
||||
|
||||
relaybot:
|
||||
# Whether or not relaybot support is enabled.
|
||||
enabled: false
|
||||
# The management room for the bot. This is where all status notifications are posted and
|
||||
# in this room, you can use `!wa <command>` instead of `!wa relaybot <command>`. Omitting
|
||||
# the command prefix completely like in user management rooms is not possible.
|
||||
management: !foo:example.com
|
||||
# List of users to invite to all created rooms that include the relaybot.
|
||||
invites: []
|
||||
# The formats to use when sending messages to WhatsApp via the relaybot.
|
||||
message_formats:
|
||||
m.text: "<b>{{ .Sender.Displayname }}</b>: {{ .Message }}"
|
||||
m.notice: "<b>{{ .Sender.Displayname }}</b>: {{ .Message }}"
|
||||
m.emote: "* <b>{{ .Sender.Displayname }}</b> {{ .Message }}"
|
||||
m.file: "<b>{{ .Sender.Displayname }}</b> sent a file"
|
||||
m.image: "<b>{{ .Sender.Displayname }}</b> sent an image"
|
||||
m.audio: "<b>{{ .Sender.Displayname }}</b> sent an audio file"
|
||||
m.video: "<b>{{ .Sender.Displayname }}</b> sent a video"
|
||||
m.location: "<b>{{ .Sender.Displayname }}</b> sent a location"
|
||||
|
||||
logging:
|
||||
timestamp_format: Jan _2, 2006 15:04:05
|
||||
print_level: debug
|
11
main.go
11
main.go
|
@ -25,6 +25,8 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/Rhymen/go-whatsapp"
|
||||
|
||||
flag "maunium.net/go/mauflag"
|
||||
log "maunium.net/go/maulogger/v2"
|
||||
|
||||
|
@ -36,7 +38,6 @@ import (
|
|||
"maunium.net/go/mautrix-whatsapp/config"
|
||||
"maunium.net/go/mautrix-whatsapp/database"
|
||||
"maunium.net/go/mautrix-whatsapp/database/upgrades"
|
||||
"maunium.net/go/mautrix-whatsapp/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -137,14 +138,14 @@ type Bridge struct {
|
|||
Metrics *MetricsHandler
|
||||
|
||||
usersByMXID map[id.UserID]*User
|
||||
usersByJID map[types.WhatsAppID]*User
|
||||
usersByJID map[whatsapp.JID]*User
|
||||
usersLock sync.Mutex
|
||||
managementRooms map[id.RoomID]*User
|
||||
managementRoomsLock sync.Mutex
|
||||
portalsByMXID map[id.RoomID]*Portal
|
||||
portalsByJID map[database.PortalKey]*Portal
|
||||
portalsLock sync.Mutex
|
||||
puppets map[types.WhatsAppID]*Puppet
|
||||
puppets map[whatsapp.JID]*Puppet
|
||||
puppetsByCustomMXID map[id.UserID]*Puppet
|
||||
puppetsLock sync.Mutex
|
||||
}
|
||||
|
@ -163,11 +164,11 @@ type Crypto interface {
|
|||
func NewBridge() *Bridge {
|
||||
bridge := &Bridge{
|
||||
usersByMXID: make(map[id.UserID]*User),
|
||||
usersByJID: make(map[types.WhatsAppID]*User),
|
||||
usersByJID: make(map[whatsapp.JID]*User),
|
||||
managementRooms: make(map[id.RoomID]*User),
|
||||
portalsByMXID: make(map[id.RoomID]*Portal),
|
||||
portalsByJID: make(map[database.PortalKey]*Portal),
|
||||
puppets: make(map[types.WhatsAppID]*Puppet),
|
||||
puppets: make(map[whatsapp.JID]*Puppet),
|
||||
puppetsByCustomMXID: make(map[id.UserID]*Puppet),
|
||||
}
|
||||
|
||||
|
|
|
@ -254,6 +254,10 @@ func (mx *MatrixHandler) HandleMembership(evt *event.Event) {
|
|||
return
|
||||
}
|
||||
|
||||
if mx.shouldIgnoreEvent(evt) {
|
||||
return
|
||||
}
|
||||
|
||||
user := mx.bridge.GetUserByMXID(evt.Sender)
|
||||
if user == nil || !user.Whitelisted || !user.IsConnected() {
|
||||
return
|
||||
|
|
21
metrics.go
21
metrics.go
|
@ -27,11 +27,12 @@ import (
|
|||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
log "maunium.net/go/maulogger/v2"
|
||||
|
||||
"github.com/Rhymen/go-whatsapp"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
|
||||
"maunium.net/go/mautrix-whatsapp/database"
|
||||
"maunium.net/go/mautrix-whatsapp/types"
|
||||
)
|
||||
|
||||
type MetricsHandler struct {
|
||||
|
@ -56,11 +57,11 @@ type MetricsHandler struct {
|
|||
unencryptedPrivateCount prometheus.Gauge
|
||||
|
||||
connected prometheus.Gauge
|
||||
connectedState map[types.WhatsAppID]bool
|
||||
connectedState map[whatsapp.JID]bool
|
||||
loggedIn prometheus.Gauge
|
||||
loggedInState map[types.WhatsAppID]bool
|
||||
loggedInState map[whatsapp.JID]bool
|
||||
syncLocked prometheus.Gauge
|
||||
syncLockedState map[types.WhatsAppID]bool
|
||||
syncLockedState map[whatsapp.JID]bool
|
||||
bufferLength *prometheus.GaugeVec
|
||||
}
|
||||
|
||||
|
@ -109,17 +110,17 @@ func NewMetricsHandler(address string, log log.Logger, db *database.Database) *M
|
|||
Name: "bridge_logged_in",
|
||||
Help: "Users logged into the bridge",
|
||||
}),
|
||||
loggedInState: make(map[types.WhatsAppID]bool),
|
||||
loggedInState: make(map[whatsapp.JID]bool),
|
||||
connected: promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "bridge_connected",
|
||||
Help: "Bridge users connected to WhatsApp",
|
||||
}),
|
||||
connectedState: make(map[types.WhatsAppID]bool),
|
||||
connectedState: make(map[whatsapp.JID]bool),
|
||||
syncLocked: promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "bridge_sync_locked",
|
||||
Help: "Bridge users locked in post-login sync",
|
||||
}),
|
||||
syncLockedState: make(map[types.WhatsAppID]bool),
|
||||
syncLockedState: make(map[whatsapp.JID]bool),
|
||||
bufferLength: promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Name: "bridge_buffer_size",
|
||||
Help: "Number of messages in buffer",
|
||||
|
@ -149,7 +150,7 @@ func (mh *MetricsHandler) TrackDisconnection(userID id.UserID) {
|
|||
mh.disconnections.With(prometheus.Labels{"user_id": string(userID)}).Inc()
|
||||
}
|
||||
|
||||
func (mh *MetricsHandler) TrackLoginState(jid types.WhatsAppID, loggedIn bool) {
|
||||
func (mh *MetricsHandler) TrackLoginState(jid whatsapp.JID, loggedIn bool) {
|
||||
if !mh.running {
|
||||
return
|
||||
}
|
||||
|
@ -164,7 +165,7 @@ func (mh *MetricsHandler) TrackLoginState(jid types.WhatsAppID, loggedIn bool) {
|
|||
}
|
||||
}
|
||||
|
||||
func (mh *MetricsHandler) TrackConnectionState(jid types.WhatsAppID, connected bool) {
|
||||
func (mh *MetricsHandler) TrackConnectionState(jid whatsapp.JID, connected bool) {
|
||||
if !mh.running {
|
||||
return
|
||||
}
|
||||
|
@ -179,7 +180,7 @@ func (mh *MetricsHandler) TrackConnectionState(jid types.WhatsAppID, connected b
|
|||
}
|
||||
}
|
||||
|
||||
func (mh *MetricsHandler) TrackSyncLock(jid types.WhatsAppID, locked bool) {
|
||||
func (mh *MetricsHandler) TrackSyncLock(jid whatsapp.JID, locked bool) {
|
||||
if !mh.running {
|
||||
return
|
||||
}
|
||||
|
|
40
portal.go
40
portal.go
|
@ -40,23 +40,19 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
log "maunium.net/go/maulogger/v2"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/attachment"
|
||||
|
||||
"github.com/Rhymen/go-whatsapp"
|
||||
waProto "github.com/Rhymen/go-whatsapp/binary/proto"
|
||||
|
||||
log "maunium.net/go/maulogger/v2"
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/appservice"
|
||||
"maunium.net/go/mautrix/crypto/attachment"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/format"
|
||||
"maunium.net/go/mautrix/id"
|
||||
"maunium.net/go/mautrix/pushrules"
|
||||
|
||||
"maunium.net/go/mautrix-whatsapp/database"
|
||||
"maunium.net/go/mautrix-whatsapp/types"
|
||||
"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
|
||||
)
|
||||
|
||||
func (bridge *Bridge) GetPortalByMXID(mxid id.RoomID) *Portal {
|
||||
|
@ -83,7 +79,7 @@ func (bridge *Bridge) GetAllPortals() []*Portal {
|
|||
return bridge.dbPortalsToPortals(bridge.DB.Portal.GetAll())
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetAllPortalsByJID(jid types.WhatsAppID) []*Portal {
|
||||
func (bridge *Bridge) GetAllPortalsByJID(jid whatsapp.JID) []*Portal {
|
||||
return bridge.dbPortalsToPortals(bridge.DB.Portal.GetAllByJID(jid))
|
||||
}
|
||||
|
||||
|
@ -131,7 +127,7 @@ func (bridge *Bridge) NewManualPortal(key database.PortalKey) *Portal {
|
|||
bridge: bridge,
|
||||
log: bridge.Log.Sub(fmt.Sprintf("Portal/%s", key)),
|
||||
|
||||
recentlyHandled: [recentlyHandledLength]types.WhatsAppMessageID{},
|
||||
recentlyHandled: [recentlyHandledLength]whatsapp.MessageID{},
|
||||
|
||||
messages: make(chan PortalMessage, bridge.Config.Bridge.PortalMessageBuffer),
|
||||
}
|
||||
|
@ -146,7 +142,7 @@ func (bridge *Bridge) NewPortal(dbPortal *database.Portal) *Portal {
|
|||
bridge: bridge,
|
||||
log: bridge.Log.Sub(fmt.Sprintf("Portal/%s", dbPortal.Key)),
|
||||
|
||||
recentlyHandled: [recentlyHandledLength]types.WhatsAppMessageID{},
|
||||
recentlyHandled: [recentlyHandledLength]whatsapp.MessageID{},
|
||||
|
||||
messages: make(chan PortalMessage, bridge.Config.Bridge.PortalMessageBuffer),
|
||||
}
|
||||
|
@ -171,7 +167,7 @@ type Portal struct {
|
|||
|
||||
roomCreateLock sync.Mutex
|
||||
|
||||
recentlyHandled [recentlyHandledLength]types.WhatsAppMessageID
|
||||
recentlyHandled [recentlyHandledLength]whatsapp.MessageID
|
||||
recentlyHandledLock sync.Mutex
|
||||
recentlyHandledIndex uint8
|
||||
|
||||
|
@ -256,7 +252,7 @@ func (portal *Portal) handleMessage(msg PortalMessage, isBackfill bool) {
|
|||
portal.HandleLocationMessage(msg.source, data)
|
||||
case whatsapp.StubMessage:
|
||||
portal.HandleStubMessage(msg.source, data, isBackfill)
|
||||
case whatsappExt.MessageRevocation:
|
||||
case whatsapp.MessageRevocation:
|
||||
portal.HandleMessageRevoke(msg.source, data)
|
||||
case FakeMessage:
|
||||
portal.HandleFakeMessage(msg.source, data)
|
||||
|
@ -265,7 +261,7 @@ func (portal *Portal) handleMessage(msg PortalMessage, isBackfill bool) {
|
|||
}
|
||||
}
|
||||
|
||||
func (portal *Portal) isRecentlyHandled(id types.WhatsAppMessageID) bool {
|
||||
func (portal *Portal) isRecentlyHandled(id whatsapp.MessageID) bool {
|
||||
start := portal.recentlyHandledIndex
|
||||
for i := start; i != start; i = (i - 1) % recentlyHandledLength {
|
||||
if portal.recentlyHandled[i] == id {
|
||||
|
@ -275,7 +271,7 @@ func (portal *Portal) isRecentlyHandled(id types.WhatsAppMessageID) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (portal *Portal) isDuplicate(id types.WhatsAppMessageID) bool {
|
||||
func (portal *Portal) isDuplicate(id whatsapp.MessageID) bool {
|
||||
msg := portal.bridge.DB.Message.GetByJID(portal.Key, id)
|
||||
if msg != nil {
|
||||
return true
|
||||
|
@ -355,7 +351,7 @@ func (portal *Portal) finishHandling(source *User, message *waProto.WebMessageIn
|
|||
portal.log.Debugln("Handled message", message.GetKey().GetId(), "->", mxid)
|
||||
}
|
||||
|
||||
func (portal *Portal) SyncParticipants(metadata *whatsappExt.GroupInfo) {
|
||||
func (portal *Portal) SyncParticipants(metadata *whatsapp.GroupInfo) {
|
||||
changed := false
|
||||
levels, err := portal.MainIntent().PowerLevels(portal.MXID)
|
||||
if err != nil {
|
||||
|
@ -413,7 +409,7 @@ func (portal *Portal) SyncParticipants(metadata *whatsappExt.GroupInfo) {
|
|||
}
|
||||
}
|
||||
|
||||
func (portal *Portal) UpdateAvatar(user *User, avatar *whatsappExt.ProfilePicInfo, updateInfo bool) bool {
|
||||
func (portal *Portal) UpdateAvatar(user *User, avatar *whatsapp.ProfilePicInfo, updateInfo bool) bool {
|
||||
if avatar == nil || (avatar.Status == 0 && avatar.Tag != "remove" && len(avatar.URL) == 0) {
|
||||
var err error
|
||||
avatar, err = user.Conn.GetProfilePicThumb(portal.Key.JID)
|
||||
|
@ -464,7 +460,7 @@ func (portal *Portal) UpdateAvatar(user *User, avatar *whatsappExt.ProfilePicInf
|
|||
return true
|
||||
}
|
||||
|
||||
func (portal *Portal) UpdateName(name string, setBy types.WhatsAppID, intent *appservice.IntentAPI, updateInfo bool) bool {
|
||||
func (portal *Portal) UpdateName(name string, setBy whatsapp.JID, intent *appservice.IntentAPI, updateInfo bool) bool {
|
||||
if portal.Name != name {
|
||||
portal.log.Debugfln("Updating name %s -> %s", portal.Name, name)
|
||||
portal.Name = name
|
||||
|
@ -488,7 +484,7 @@ func (portal *Portal) UpdateName(name string, setBy types.WhatsAppID, intent *ap
|
|||
return false
|
||||
}
|
||||
|
||||
func (portal *Portal) UpdateTopic(topic string, setBy types.WhatsAppID, intent *appservice.IntentAPI, updateInfo bool) bool {
|
||||
func (portal *Portal) UpdateTopic(topic string, setBy whatsapp.JID, intent *appservice.IntentAPI, updateInfo bool) bool {
|
||||
if portal.Topic != topic {
|
||||
portal.log.Debugfln("Updating topic %s -> %s", portal.Topic, topic)
|
||||
portal.Topic = topic
|
||||
|
@ -974,7 +970,7 @@ func (portal *Portal) CreateMatrixRoom(user *User) error {
|
|||
|
||||
portal.log.Infoln("Creating Matrix room. Info source:", user.MXID)
|
||||
|
||||
var metadata *whatsappExt.GroupInfo
|
||||
var metadata *whatsapp.GroupInfo
|
||||
if portal.IsPrivateChat() {
|
||||
puppet := portal.bridge.GetPuppetByJID(portal.Key.JID)
|
||||
if portal.bridge.Config.Bridge.PrivateChatPortalMeta {
|
||||
|
@ -1099,7 +1095,7 @@ func (portal *Portal) CreateMatrixRoom(user *User) error {
|
|||
|
||||
func (portal *Portal) IsPrivateChat() bool {
|
||||
if portal.isPrivate == nil {
|
||||
val := strings.HasSuffix(portal.Key.JID, whatsappExt.NewUserSuffix)
|
||||
val := strings.HasSuffix(portal.Key.JID, whatsapp.NewUserSuffix)
|
||||
portal.isPrivate = &val
|
||||
}
|
||||
return *portal.isPrivate
|
||||
|
@ -1152,7 +1148,7 @@ func (portal *Portal) SetReply(content *event.MessageEventContent, info whatsapp
|
|||
return
|
||||
}
|
||||
|
||||
func (portal *Portal) HandleMessageRevoke(user *User, message whatsappExt.MessageRevocation) {
|
||||
func (portal *Portal) HandleMessageRevoke(user *User, message whatsapp.MessageRevocation) {
|
||||
msg := portal.bridge.DB.Message.GetByJID(portal.Key, message.Id)
|
||||
if msg == nil || msg.IsFakeMXID() {
|
||||
return
|
||||
|
@ -1794,7 +1790,7 @@ func (portal *Portal) convertGifToVideo(gif []byte) ([]byte, error) {
|
|||
|
||||
func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool, content *event.MessageEventContent, eventID id.EventID, mediaType whatsapp.MediaType) *MediaUpload {
|
||||
var caption string
|
||||
var mentionedJIDs []types.WhatsAppID
|
||||
var mentionedJIDs []whatsapp.JID
|
||||
if relaybotFormatted {
|
||||
caption, mentionedJIDs = portal.bridge.Formatter.ParseMatrix(content.FormattedBody)
|
||||
}
|
||||
|
@ -1851,7 +1847,7 @@ func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool
|
|||
|
||||
type MediaUpload struct {
|
||||
Caption string
|
||||
MentionedJIDs []types.WhatsAppID
|
||||
MentionedJIDs []whatsapp.JID
|
||||
URL string
|
||||
MediaKey []byte
|
||||
FileEncSHA256 []byte
|
||||
|
|
|
@ -27,12 +27,11 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
log "maunium.net/go/maulogger/v2"
|
||||
|
||||
"github.com/Rhymen/go-whatsapp"
|
||||
"maunium.net/go/mautrix/id"
|
||||
|
||||
whatsappExt "maunium.net/go/mautrix-whatsapp/whatsapp-ext"
|
||||
log "maunium.net/go/maulogger/v2"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type ProvisioningAPI struct {
|
||||
|
@ -433,7 +432,7 @@ func (prov *ProvisioningAPI) Login(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
user.log.Debugln("Successful login via provisioning API")
|
||||
user.ConnectionErrors = 0
|
||||
user.JID = strings.Replace(user.Conn.Info.Wid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, 1)
|
||||
user.JID = strings.Replace(user.Conn.Info.Wid, whatsapp.OldUserSuffix, whatsapp.NewUserSuffix, 1)
|
||||
user.addToJIDMap()
|
||||
user.SetSession(&session)
|
||||
_ = c.WriteJSON(map[string]interface{}{
|
||||
|
|
19
puppet.go
19
puppet.go
|
@ -22,21 +22,18 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
|
||||
log "maunium.net/go/maulogger/v2"
|
||||
|
||||
"github.com/Rhymen/go-whatsapp"
|
||||
|
||||
log "maunium.net/go/maulogger/v2"
|
||||
"maunium.net/go/mautrix/appservice"
|
||||
"maunium.net/go/mautrix/id"
|
||||
|
||||
"maunium.net/go/mautrix-whatsapp/database"
|
||||
"maunium.net/go/mautrix-whatsapp/types"
|
||||
"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
|
||||
)
|
||||
|
||||
var userIDRegex *regexp.Regexp
|
||||
|
||||
func (bridge *Bridge) ParsePuppetMXID(mxid id.UserID) (types.WhatsAppID, bool) {
|
||||
func (bridge *Bridge) ParsePuppetMXID(mxid id.UserID) (whatsapp.JID, bool) {
|
||||
if userIDRegex == nil {
|
||||
userIDRegex = regexp.MustCompile(fmt.Sprintf("^@%s:%s$",
|
||||
bridge.Config.Bridge.FormatUsername("([0-9]+)"),
|
||||
|
@ -47,7 +44,7 @@ func (bridge *Bridge) ParsePuppetMXID(mxid id.UserID) (types.WhatsAppID, bool) {
|
|||
return "", false
|
||||
}
|
||||
|
||||
jid := types.WhatsAppID(match[1] + whatsappExt.NewUserSuffix)
|
||||
jid := whatsapp.JID(match[1] + whatsapp.NewUserSuffix)
|
||||
return jid, true
|
||||
}
|
||||
|
||||
|
@ -60,7 +57,7 @@ func (bridge *Bridge) GetPuppetByMXID(mxid id.UserID) *Puppet {
|
|||
return bridge.GetPuppetByJID(jid)
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetPuppetByJID(jid types.WhatsAppID) *Puppet {
|
||||
func (bridge *Bridge) GetPuppetByJID(jid whatsapp.JID) *Puppet {
|
||||
bridge.puppetsLock.Lock()
|
||||
defer bridge.puppetsLock.Unlock()
|
||||
puppet, ok := bridge.puppets[jid]
|
||||
|
@ -125,12 +122,12 @@ func (bridge *Bridge) dbPuppetsToPuppets(dbPuppets []*database.Puppet) []*Puppet
|
|||
return output
|
||||
}
|
||||
|
||||
func (bridge *Bridge) FormatPuppetMXID(jid types.WhatsAppID) id.UserID {
|
||||
func (bridge *Bridge) FormatPuppetMXID(jid whatsapp.JID) id.UserID {
|
||||
return id.NewUserID(
|
||||
bridge.Config.Bridge.FormatUsername(
|
||||
strings.Replace(
|
||||
jid,
|
||||
whatsappExt.NewUserSuffix, "", 1)),
|
||||
whatsapp.NewUserSuffix, "", 1)),
|
||||
bridge.Config.Homeserver.Domain)
|
||||
}
|
||||
|
||||
|
@ -161,7 +158,7 @@ type Puppet struct {
|
|||
}
|
||||
|
||||
func (puppet *Puppet) PhoneNumber() string {
|
||||
return strings.Replace(puppet.JID, whatsappExt.NewUserSuffix, "", 1)
|
||||
return strings.Replace(puppet.JID, whatsapp.NewUserSuffix, "", 1)
|
||||
}
|
||||
|
||||
func (puppet *Puppet) IntentFor(portal *Portal) *appservice.IntentAPI {
|
||||
|
@ -181,7 +178,7 @@ func (puppet *Puppet) DefaultIntent() *appservice.IntentAPI {
|
|||
return puppet.bridge.AS.Intent(puppet.MXID)
|
||||
}
|
||||
|
||||
func (puppet *Puppet) UpdateAvatar(source *User, avatar *whatsappExt.ProfilePicInfo) bool {
|
||||
func (puppet *Puppet) UpdateAvatar(source *User, avatar *whatsapp.ProfilePicInfo) bool {
|
||||
if avatar == nil {
|
||||
var err error
|
||||
avatar, err = source.Conn.GetProfilePicThumb(puppet.JID)
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
// mautrix-whatsapp - 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 types
|
||||
|
||||
// WhatsAppID is a WhatsApp JID.
|
||||
type WhatsAppID = string
|
||||
|
||||
// WhatsAppMessageID is the internal ID of a WhatsApp message.
|
||||
type WhatsAppMessageID = string
|
238
user.go
238
user.go
|
@ -40,13 +40,11 @@ import (
|
|||
"maunium.net/go/mautrix/id"
|
||||
|
||||
"maunium.net/go/mautrix-whatsapp/database"
|
||||
"maunium.net/go/mautrix-whatsapp/types"
|
||||
"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
*database.User
|
||||
Conn *whatsappExt.ExtendedConn
|
||||
Conn *whatsapp.Conn
|
||||
|
||||
bridge *Bridge
|
||||
log log.Logger
|
||||
|
@ -91,7 +89,7 @@ func (bridge *Bridge) GetUserByMXID(userID id.UserID) *User {
|
|||
return user
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetUserByJID(userID types.WhatsAppID) *User {
|
||||
func (bridge *Bridge) GetUserByJID(userID whatsapp.JID) *User {
|
||||
bridge.usersLock.Lock()
|
||||
defer bridge.usersLock.Unlock()
|
||||
user, ok := bridge.usersByJID[userID]
|
||||
|
@ -264,7 +262,7 @@ func (user *User) Connect(evenIfNoSession bool) bool {
|
|||
user.connLock.Unlock()
|
||||
return false
|
||||
}
|
||||
user.Conn = whatsappExt.ExtendConn(conn)
|
||||
user.Conn = conn
|
||||
user.log.Debugln("WhatsApp connection successful")
|
||||
user.Conn.AddHandler(user)
|
||||
user.connLock.Unlock()
|
||||
|
@ -419,7 +417,7 @@ func (user *User) Login(ce *CommandEvent) {
|
|||
// TODO there's a bit of duplication between this and the provisioning API login method
|
||||
// Also between the two logout methods (commands.go and provisioning.go)
|
||||
user.ConnectionErrors = 0
|
||||
user.JID = strings.Replace(user.Conn.Info.Wid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, 1)
|
||||
user.JID = strings.Replace(user.Conn.Info.Wid, whatsapp.OldUserSuffix, whatsapp.NewUserSuffix, 1)
|
||||
user.addToJIDMap()
|
||||
user.SetSession(&session)
|
||||
ce.Reply("Successfully logged in, synchronizing chats...")
|
||||
|
@ -501,7 +499,7 @@ func (user *User) sendMarkdownBridgeAlert(formatString string, args ...interface
|
|||
}
|
||||
}
|
||||
|
||||
func (user *User) postConnPing(conn *whatsappExt.ExtendedConn) bool {
|
||||
func (user *User) postConnPing(conn *whatsapp.Conn) bool {
|
||||
if user.Conn != conn {
|
||||
user.log.Warnln("Connection changed before scheduled post-connection ping, canceling ping")
|
||||
return false
|
||||
|
@ -528,7 +526,7 @@ func (user *User) postConnPing(conn *whatsappExt.ExtendedConn) bool {
|
|||
}
|
||||
}
|
||||
|
||||
func (user *User) intPostLogin(conn *whatsappExt.ExtendedConn) {
|
||||
func (user *User) intPostLogin(conn *whatsapp.Conn) {
|
||||
defer user.syncWait.Done()
|
||||
user.lastReconnection = time.Now().Unix()
|
||||
user.createCommunity()
|
||||
|
@ -559,8 +557,60 @@ func (user *User) intPostLogin(conn *whatsappExt.ExtendedConn) {
|
|||
}
|
||||
}
|
||||
|
||||
func (user *User) HandleStreamEvent(evt whatsappExt.StreamEvent) {
|
||||
if evt.Type == whatsappExt.StreamSleep {
|
||||
type InfoGetter interface {
|
||||
GetInfo() whatsapp.MessageInfo
|
||||
}
|
||||
|
||||
func (user *User) HandleEvent(event interface{}) {
|
||||
switch v := event.(type) {
|
||||
case whatsapp.TextMessage, whatsapp.ImageMessage, whatsapp.StickerMessage, whatsapp.VideoMessage,
|
||||
whatsapp.AudioMessage, whatsapp.DocumentMessage, whatsapp.ContactMessage, whatsapp.StubMessage,
|
||||
whatsapp.LocationMessage:
|
||||
info := v.(InfoGetter).GetInfo()
|
||||
user.messageInput <- PortalMessage{info.RemoteJid, user, v, info.Timestamp}
|
||||
case whatsapp.MessageRevocation:
|
||||
user.messageInput <- PortalMessage{v.RemoteJid, user, v, 0}
|
||||
case whatsapp.StreamEvent:
|
||||
user.HandleStreamEvent(v)
|
||||
case []whatsapp.Chat:
|
||||
user.HandleChatList(v)
|
||||
case []whatsapp.Contact:
|
||||
user.HandleContactList(v)
|
||||
case error:
|
||||
user.HandleError(v)
|
||||
case whatsapp.Contact:
|
||||
go user.HandleNewContact(v)
|
||||
case whatsapp.BatteryMessage:
|
||||
user.HandleBatteryMessage(v)
|
||||
case whatsapp.CallInfo:
|
||||
user.HandleCallInfo(v)
|
||||
case whatsapp.PresenceEvent:
|
||||
go user.HandlePresence(v)
|
||||
case whatsapp.JSONMsgInfo:
|
||||
go user.HandleMsgInfo(v)
|
||||
case whatsapp.ReceivedMessage:
|
||||
user.HandleReceivedMessage(v)
|
||||
case whatsapp.ReadMessage:
|
||||
user.HandleReadMessage(v)
|
||||
case whatsapp.JSONCommand:
|
||||
user.HandleCommand(v)
|
||||
case whatsapp.ChatUpdate:
|
||||
user.HandleChatUpdate(v)
|
||||
case json.RawMessage:
|
||||
user.HandleJSONMessage(v)
|
||||
case *waProto.WebMessageInfo:
|
||||
user.updateLastConnectionIfNecessary()
|
||||
// TODO trace log
|
||||
user.log.Debugfln("WebMessageInfo: %+v", v)
|
||||
case *waBinary.Node:
|
||||
user.log.Debugfln("Unknown binary message: %+v", v)
|
||||
default:
|
||||
user.log.Debugfln("Unknown type of event in HandleEvent: %T", v)
|
||||
}
|
||||
}
|
||||
|
||||
func (user *User) HandleStreamEvent(evt whatsapp.StreamEvent) {
|
||||
if evt.Type == whatsapp.StreamSleep {
|
||||
if user.lastReconnection+60 > time.Now().Unix() {
|
||||
user.lastReconnection = 0
|
||||
user.log.Infoln("Stream went to sleep soon after reconnection, making new post-connection ping in 20 seconds")
|
||||
|
@ -738,7 +788,7 @@ func (user *User) syncPuppets(contacts map[string]whatsapp.Contact) {
|
|||
}
|
||||
user.log.Infoln("Syncing puppet info from contacts")
|
||||
for jid, contact := range contacts {
|
||||
if strings.HasSuffix(jid, whatsappExt.NewUserSuffix) {
|
||||
if strings.HasSuffix(jid, whatsapp.NewUserSuffix) {
|
||||
puppet := user.bridge.GetPuppetByJID(contact.Jid)
|
||||
puppet.Sync(user, contact)
|
||||
}
|
||||
|
@ -841,19 +891,11 @@ func (user *User) tryReconnect(msg string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (user *User) ShouldCallSynchronously() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (user *User) HandleJSONParseError(err error) {
|
||||
user.log.Errorln("WhatsApp JSON parse error:", err)
|
||||
}
|
||||
|
||||
func (user *User) PortalKey(jid types.WhatsAppID) database.PortalKey {
|
||||
func (user *User) PortalKey(jid whatsapp.JID) database.PortalKey {
|
||||
return database.NewPortalKey(jid, user.JID)
|
||||
}
|
||||
|
||||
func (user *User) GetPortalByJID(jid types.WhatsAppID) *Portal {
|
||||
func (user *User) GetPortalByJID(jid whatsapp.JID) *Portal {
|
||||
return user.bridge.GetPortalByJID(user.PortalKey(jid))
|
||||
}
|
||||
|
||||
|
@ -888,13 +930,11 @@ func (user *User) handleMessageLoop() {
|
|||
|
||||
func (user *User) HandleNewContact(contact whatsapp.Contact) {
|
||||
user.log.Debugfln("Contact message: %+v", contact)
|
||||
go func() {
|
||||
if strings.HasSuffix(contact.Jid, whatsappExt.OldUserSuffix) {
|
||||
contact.Jid = strings.Replace(contact.Jid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, -1)
|
||||
}
|
||||
puppet := user.bridge.GetPuppetByJID(contact.Jid)
|
||||
puppet.UpdateName(user, contact)
|
||||
}()
|
||||
if strings.HasSuffix(contact.Jid, whatsapp.OldUserSuffix) {
|
||||
contact.Jid = strings.Replace(contact.Jid, whatsapp.OldUserSuffix, whatsapp.NewUserSuffix, -1)
|
||||
}
|
||||
puppet := user.bridge.GetPuppetByJID(contact.Jid)
|
||||
puppet.UpdateName(user, contact)
|
||||
}
|
||||
|
||||
func (user *User) HandleBatteryMessage(battery whatsapp.BatteryMessage) {
|
||||
|
@ -914,53 +954,13 @@ func (user *User) HandleBatteryMessage(battery whatsapp.BatteryMessage) {
|
|||
}
|
||||
}
|
||||
|
||||
func (user *User) HandleTextMessage(message whatsapp.TextMessage) {
|
||||
user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
||||
}
|
||||
|
||||
func (user *User) HandleImageMessage(message whatsapp.ImageMessage) {
|
||||
user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
||||
}
|
||||
|
||||
func (user *User) HandleStickerMessage(message whatsapp.StickerMessage) {
|
||||
user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
||||
}
|
||||
|
||||
func (user *User) HandleVideoMessage(message whatsapp.VideoMessage) {
|
||||
user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
||||
}
|
||||
|
||||
func (user *User) HandleAudioMessage(message whatsapp.AudioMessage) {
|
||||
user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
||||
}
|
||||
|
||||
func (user *User) HandleDocumentMessage(message whatsapp.DocumentMessage) {
|
||||
user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
||||
}
|
||||
|
||||
func (user *User) HandleContactMessage(message whatsapp.ContactMessage) {
|
||||
user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
||||
}
|
||||
|
||||
func (user *User) HandleStubMessage(message whatsapp.StubMessage) {
|
||||
user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
||||
}
|
||||
|
||||
func (user *User) HandleLocationMessage(message whatsapp.LocationMessage) {
|
||||
user.messageInput <- PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}
|
||||
}
|
||||
|
||||
func (user *User) HandleMessageRevoke(message whatsappExt.MessageRevocation) {
|
||||
user.messageInput <- PortalMessage{message.RemoteJid, user, message, 0}
|
||||
}
|
||||
|
||||
type FakeMessage struct {
|
||||
Text string
|
||||
ID string
|
||||
Alert bool
|
||||
}
|
||||
|
||||
func (user *User) HandleCallInfo(info whatsappExt.CallInfo) {
|
||||
func (user *User) HandleCallInfo(info whatsapp.CallInfo) {
|
||||
if info.Data != nil {
|
||||
return
|
||||
}
|
||||
|
@ -968,19 +968,19 @@ func (user *User) HandleCallInfo(info whatsappExt.CallInfo) {
|
|||
ID: info.ID,
|
||||
}
|
||||
switch info.Type {
|
||||
case whatsappExt.CallOffer:
|
||||
case whatsapp.CallOffer:
|
||||
if !user.bridge.Config.Bridge.CallNotices.Start {
|
||||
return
|
||||
}
|
||||
data.Text = "Incoming call"
|
||||
data.Alert = true
|
||||
case whatsappExt.CallOfferVideo:
|
||||
case whatsapp.CallOfferVideo:
|
||||
if !user.bridge.Config.Bridge.CallNotices.Start {
|
||||
return
|
||||
}
|
||||
data.Text = "Incoming video call"
|
||||
data.Alert = true
|
||||
case whatsappExt.CallTerminate:
|
||||
case whatsapp.CallTerminate:
|
||||
if !user.bridge.Config.Bridge.CallNotices.End {
|
||||
return
|
||||
}
|
||||
|
@ -995,7 +995,7 @@ func (user *User) HandleCallInfo(info whatsappExt.CallInfo) {
|
|||
}
|
||||
}
|
||||
|
||||
func (user *User) HandlePresence(info whatsappExt.Presence) {
|
||||
func (user *User) HandlePresence(info whatsapp.PresenceEvent) {
|
||||
puppet := user.bridge.GetPuppetByJID(info.SenderJID)
|
||||
switch info.Status {
|
||||
case whatsapp.PresenceUnavailable:
|
||||
|
@ -1023,33 +1023,31 @@ func (user *User) HandlePresence(info whatsappExt.Presence) {
|
|||
}
|
||||
}
|
||||
|
||||
func (user *User) HandleMsgInfo(info whatsappExt.MsgInfo) {
|
||||
if (info.Command == whatsappExt.MsgInfoCommandAck || info.Command == whatsappExt.MsgInfoCommandAcks) && info.Acknowledgement == whatsappExt.AckMessageRead {
|
||||
func (user *User) HandleMsgInfo(info whatsapp.JSONMsgInfo) {
|
||||
if (info.Command == whatsapp.MsgInfoCommandAck || info.Command == whatsapp.MsgInfoCommandAcks) && info.Acknowledgement == whatsapp.AckMessageRead {
|
||||
portal := user.GetPortalByJID(info.ToJID)
|
||||
if len(portal.MXID) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
intent := user.bridge.GetPuppetByJID(info.SenderJID).IntentFor(portal)
|
||||
for _, msgID := range info.IDs {
|
||||
msg := user.bridge.DB.Message.GetByJID(portal.Key, msgID)
|
||||
if msg == nil || msg.IsFakeMXID() {
|
||||
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)
|
||||
}
|
||||
intent := user.bridge.GetPuppetByJID(info.SenderJID).IntentFor(portal)
|
||||
for _, msgID := range info.IDs {
|
||||
msg := user.bridge.DB.Message.GetByJID(portal.Key, msgID)
|
||||
if msg == nil || msg.IsFakeMXID() {
|
||||
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) HandleReceivedMessage(received whatsapp.ReceivedMessage) {
|
||||
if received.Type == "read" {
|
||||
user.markSelfRead(received.Jid, received.Index)
|
||||
go user.markSelfRead(received.Jid, received.Index)
|
||||
} else {
|
||||
user.log.Debugfln("Unknown received message type: %+v", received)
|
||||
}
|
||||
|
@ -1057,12 +1055,12 @@ func (user *User) HandleReceivedMessage(received whatsapp.ReceivedMessage) {
|
|||
|
||||
func (user *User) HandleReadMessage(read whatsapp.ReadMessage) {
|
||||
user.log.Debugfln("Received chat read message: %+v", read)
|
||||
user.markSelfRead(read.Jid, "")
|
||||
go user.markSelfRead(read.Jid, "")
|
||||
}
|
||||
|
||||
func (user *User) markSelfRead(jid, messageID string) {
|
||||
if strings.HasSuffix(jid, whatsappExt.OldUserSuffix) {
|
||||
jid = strings.Replace(jid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, -1)
|
||||
if strings.HasSuffix(jid, whatsapp.OldUserSuffix) {
|
||||
jid = strings.Replace(jid, whatsapp.OldUserSuffix, whatsapp.NewUserSuffix, -1)
|
||||
}
|
||||
puppet := user.bridge.GetPuppetByJID(user.JID)
|
||||
if puppet == nil {
|
||||
|
@ -1096,17 +1094,17 @@ func (user *User) markSelfRead(jid, messageID string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (user *User) HandleCommand(cmd whatsappExt.Command) {
|
||||
func (user *User) HandleCommand(cmd whatsapp.JSONCommand) {
|
||||
switch cmd.Type {
|
||||
case whatsappExt.CommandPicture:
|
||||
if strings.HasSuffix(cmd.JID, whatsappExt.NewUserSuffix) {
|
||||
case whatsapp.CommandPicture:
|
||||
if strings.HasSuffix(cmd.JID, whatsapp.NewUserSuffix) {
|
||||
puppet := user.bridge.GetPuppetByJID(cmd.JID)
|
||||
go puppet.UpdateAvatar(user, cmd.ProfilePicInfo)
|
||||
} else if user.bridge.Config.Bridge.ChatMetaSync {
|
||||
portal := user.GetPortalByJID(cmd.JID)
|
||||
go portal.UpdateAvatar(user, cmd.ProfilePicInfo, true)
|
||||
}
|
||||
case whatsappExt.CommandDisconnect:
|
||||
case whatsapp.CommandDisconnect:
|
||||
if cmd.Kind == "replaced" {
|
||||
user.cleanDisconnection = true
|
||||
go user.sendMarkdownBridgeAlert("\u26a0 Your WhatsApp connection was closed by the server because you opened another WhatsApp Web client.\n\n" +
|
||||
|
@ -1119,14 +1117,14 @@ func (user *User) HandleCommand(cmd whatsappExt.Command) {
|
|||
}
|
||||
}
|
||||
|
||||
func (user *User) HandleChatUpdate(cmd whatsappExt.ChatUpdate) {
|
||||
if cmd.Command != whatsappExt.ChatUpdateCommandAction {
|
||||
func (user *User) HandleChatUpdate(cmd whatsapp.ChatUpdate) {
|
||||
if cmd.Command != whatsapp.ChatUpdateCommandAction {
|
||||
return
|
||||
}
|
||||
|
||||
portal := user.GetPortalByJID(cmd.JID)
|
||||
if len(portal.MXID) == 0 {
|
||||
if cmd.Data.Action == whatsappExt.ChatActionIntroduce || cmd.Data.Action == whatsappExt.ChatActionCreate {
|
||||
if cmd.Data.Action == whatsapp.ChatActionIntroduce || cmd.Data.Action == whatsapp.ChatActionCreate {
|
||||
go func() {
|
||||
err := portal.CreateMatrixRoom(user)
|
||||
if err != nil {
|
||||
|
@ -1139,11 +1137,11 @@ func (user *User) HandleChatUpdate(cmd whatsappExt.ChatUpdate) {
|
|||
|
||||
// These don't come down the message history :(
|
||||
switch cmd.Data.Action {
|
||||
case whatsappExt.ChatActionAddTopic:
|
||||
go portal.UpdateTopic(cmd.Data.AddTopic.Topic, cmd.Data.SenderJID, nil,true)
|
||||
case whatsappExt.ChatActionRemoveTopic:
|
||||
go portal.UpdateTopic("", cmd.Data.SenderJID, nil,true)
|
||||
case whatsappExt.ChatActionRemove:
|
||||
case whatsapp.ChatActionAddTopic:
|
||||
go portal.UpdateTopic(cmd.Data.AddTopic.Topic, cmd.Data.SenderJID, nil, true)
|
||||
case whatsapp.ChatActionRemoveTopic:
|
||||
go portal.UpdateTopic("", cmd.Data.SenderJID, nil, true)
|
||||
case whatsapp.ChatActionRemove:
|
||||
// We ignore leaving groups in the message history to avoid accidentally leaving rejoined groups,
|
||||
// but if we get a real-time command that says we left, it should be safe to bridge it.
|
||||
if !user.bridge.Config.Bridge.ChatMetaSync {
|
||||
|
@ -1162,45 +1160,35 @@ func (user *User) HandleChatUpdate(cmd whatsappExt.ChatUpdate) {
|
|||
}
|
||||
|
||||
switch cmd.Data.Action {
|
||||
case whatsappExt.ChatActionNameChange:
|
||||
case whatsapp.ChatActionNameChange:
|
||||
go portal.UpdateName(cmd.Data.NameChange.Name, cmd.Data.SenderJID, nil, true)
|
||||
case whatsappExt.ChatActionPromote:
|
||||
case whatsapp.ChatActionPromote:
|
||||
go portal.ChangeAdminStatus(cmd.Data.UserChange.JIDs, true)
|
||||
case whatsappExt.ChatActionDemote:
|
||||
case whatsapp.ChatActionDemote:
|
||||
go portal.ChangeAdminStatus(cmd.Data.UserChange.JIDs, false)
|
||||
case whatsappExt.ChatActionAnnounce:
|
||||
case whatsapp.ChatActionAnnounce:
|
||||
go portal.RestrictMessageSending(cmd.Data.Announce)
|
||||
case whatsappExt.ChatActionRestrict:
|
||||
case whatsapp.ChatActionRestrict:
|
||||
go portal.RestrictMetadataChanges(cmd.Data.Restrict)
|
||||
case whatsappExt.ChatActionRemove:
|
||||
case whatsapp.ChatActionRemove:
|
||||
go portal.HandleWhatsAppKick(nil, cmd.Data.SenderJID, cmd.Data.UserChange.JIDs)
|
||||
case whatsappExt.ChatActionAdd:
|
||||
case whatsapp.ChatActionAdd:
|
||||
go portal.HandleWhatsAppInvite(cmd.Data.SenderJID, nil, cmd.Data.UserChange.JIDs)
|
||||
case whatsappExt.ChatActionIntroduce:
|
||||
case whatsapp.ChatActionIntroduce:
|
||||
if cmd.Data.SenderJID != "unknown" {
|
||||
go portal.Sync(user, whatsapp.Contact{Jid: portal.Key.JID})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (user *User) HandleJsonMessage(message string) {
|
||||
var msg json.RawMessage
|
||||
err := json.Unmarshal([]byte(message), &msg)
|
||||
if err != nil {
|
||||
func (user *User) HandleJSONMessage(message json.RawMessage) {
|
||||
if !json.Valid(message) {
|
||||
return
|
||||
}
|
||||
user.log.Debugln("JSON message:", message)
|
||||
user.log.Debugfln("JSON message: %s", message)
|
||||
user.updateLastConnectionIfNecessary()
|
||||
}
|
||||
|
||||
func (user *User) HandleRawMessage(message *waProto.WebMessageInfo) {
|
||||
user.updateLastConnectionIfNecessary()
|
||||
}
|
||||
|
||||
func (user *User) HandleUnknownBinaryNode(node *waBinary.Node) {
|
||||
user.log.Debugfln("Unknown binary message: %+v", node)
|
||||
}
|
||||
|
||||
func (user *User) NeedsRelaybot(portal *Portal) bool {
|
||||
return !user.HasSession() || !user.IsInPortal(portal.Key)
|
||||
}
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
// mautrix-whatsapp - 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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,183 +0,0 @@
|
|||
// mautrix-whatsapp - 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"
|
||||
ChatActionIntroduce ChatActionType = "introduce"
|
||||
ChatActionCreate ChatActionType = "create"
|
||||
ChatActionRemove ChatActionType = "remove"
|
||||
ChatActionAdd ChatActionType = "add"
|
||||
)
|
||||
|
||||
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"`
|
||||
SetBy string `json:"descOwner"`
|
||||
}
|
||||
|
||||
RemoveTopic struct {
|
||||
ID string `json:"descId"`
|
||||
}
|
||||
|
||||
Introduce struct {
|
||||
CreationTime int64 `json:"creation"`
|
||||
Admins []string `json:"admins"`
|
||||
SuperAdmins []string `json:"superadmins"`
|
||||
Regulars []string `json:"regulars"`
|
||||
}
|
||||
|
||||
Restrict bool
|
||||
|
||||
Announce bool
|
||||
|
||||
UserChange struct {
|
||||
JIDs []string `json:"participants"`
|
||||
}
|
||||
}
|
||||
|
||||
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 ChatActionIntroduce, ChatActionCreate:
|
||||
err = json.Unmarshal(arr[2], &cud.NameChange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(arr[2], &cud.AddTopic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
unmarshalTo = &cud.Introduce
|
||||
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, ChatActionRemove, ChatActionAdd:
|
||||
unmarshalTo = &cud.UserChange
|
||||
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.UserChange.JIDs {
|
||||
cud.UserChange.JIDs[index] = strings.Replace(jid, OldUserSuffix, NewUserSuffix, 1)
|
||||
}
|
||||
for index, jid := range cud.Introduce.SuperAdmins {
|
||||
cud.Introduce.SuperAdmins[index] = strings.Replace(jid, OldUserSuffix, NewUserSuffix, 1)
|
||||
}
|
||||
for index, jid := range cud.Introduce.Admins {
|
||||
cud.Introduce.Admins[index] = strings.Replace(jid, OldUserSuffix, NewUserSuffix, 1)
|
||||
}
|
||||
for index, jid := range cud.Introduce.Regulars {
|
||||
cud.Introduce.Regulars[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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
// mautrix-whatsapp - 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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
// mautrix-whatsapp - 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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
// mautrix-whatsapp - 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"
|
||||
|
||||
"maunium.net/go/mautrix-whatsapp/types"
|
||||
)
|
||||
|
||||
type CreateGroupResponse struct {
|
||||
Status int `json:"status"`
|
||||
GroupID types.WhatsAppID `json:"gid"`
|
||||
Participants map[types.WhatsAppID]struct {
|
||||
Code string `json:"code"`
|
||||
} `json:"participants"`
|
||||
|
||||
Source string `json:"-"`
|
||||
}
|
||||
|
||||
type actualCreateGroupResponse struct {
|
||||
Status int `json:"status"`
|
||||
GroupID types.WhatsAppID `json:"gid"`
|
||||
Participants []map[types.WhatsAppID]struct {
|
||||
Code string `json:"code"`
|
||||
} `json:"participants"`
|
||||
}
|
||||
|
||||
func (ext *ExtendedConn) CreateGroup(subject string, participants []types.WhatsAppID) (*CreateGroupResponse, error) {
|
||||
respChan, err := ext.Conn.CreateGroup(subject, participants)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var resp CreateGroupResponse
|
||||
var actualResp actualCreateGroupResponse
|
||||
resp.Source = <-respChan
|
||||
fmt.Println(">>>>>>", resp.Source)
|
||||
err = json.Unmarshal([]byte(resp.Source), &actualResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Status = actualResp.Status
|
||||
resp.GroupID = actualResp.GroupID
|
||||
resp.Participants = make(map[types.WhatsAppID]struct {
|
||||
Code string `json:"code"`
|
||||
})
|
||||
for _, participantMap := range actualResp.Participants {
|
||||
for jid, status := range participantMap {
|
||||
resp.Participants[jid] = status
|
||||
}
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
// mautrix-whatsapp - 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
// mautrix-whatsapp - 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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
// mautrix-whatsapp - 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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
// mautrix-whatsapp - 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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
// mautrix-whatsapp - 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
// mautrix-whatsapp - 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
|
||||
|
||||
IsOutdated bool
|
||||
Version string
|
||||
|
||||
Extra []json.RawMessage
|
||||
}
|
||||
|
||||
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) >= 3 {
|
||||
_ = json.Unmarshal(message[1], &event.IsOutdated)
|
||||
_ = json.Unmarshal(message[2], &event.Version)
|
||||
if len(message) >= 4 {
|
||||
event.Extra = message[3:]
|
||||
}
|
||||
} else if len(message) >= 2 {
|
||||
event.Extra = message[1:]
|
||||
}
|
||||
|
||||
for _, handler := range ext.handlers {
|
||||
streamHandler, ok := handler.(StreamEventHandler)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if ext.shouldCallSynchronously(streamHandler) {
|
||||
streamHandler.HandleStreamEvent(event)
|
||||
} else {
|
||||
go streamHandler.HandleStreamEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
// mautrix-whatsapp - 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"
|
||||
)
|
||||
|
||||
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"`
|
||||
|
||||
Announce bool `json:"announce"` // Can only admins send messages?
|
||||
|
||||
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 int `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
|
||||
}
|
Loading…
Reference in a new issue