telegabber/xmpp/handlers.go

279 lines
5.6 KiB
Go
Raw Normal View History

2019-10-22 16:36:54 +00:00
package xmpp
import (
2019-12-10 18:34:55 +00:00
"bytes"
"encoding/base64"
"github.com/pkg/errors"
2019-12-10 18:34:55 +00:00
"io"
"os"
2019-11-24 17:10:29 +00:00
"strconv"
"strings"
2019-11-19 20:25:14 +00:00
"dev.narayana.im/narayana/telegabber/persistence"
2019-12-10 18:34:55 +00:00
"dev.narayana.im/narayana/telegabber/xmpp/extensions"
2019-11-24 17:10:29 +00:00
"dev.narayana.im/narayana/telegabber/xmpp/gateway"
2019-11-19 20:25:14 +00:00
log "github.com/sirupsen/logrus"
2019-10-22 16:36:54 +00:00
"gosrc.io/xmpp"
"gosrc.io/xmpp/stanza"
)
func logPacketType(p stanza.Packet) {
2019-11-14 20:11:38 +00:00
log.Warnf("Ignoring packet: %T\n", p)
}
// HandleIq processes an incoming XMPP iq
func HandleIq(s xmpp.Sender, p stanza.Packet) {
iq, ok := p.(*stanza.IQ)
if !ok {
logPacketType(p)
return
}
2019-12-10 18:34:55 +00:00
log.Debugf("%#v", iq)
if iq.Type == "get" {
_, ok := iq.Payload.(*extensions.IqVcardTemp)
if ok {
2019-12-19 20:58:20 +00:00
go handleGetVcardTempIq(s, iq)
2019-12-10 18:34:55 +00:00
}
}
}
2019-10-29 01:23:57 +00:00
// HandleMessage processes an incoming XMPP message
2019-10-22 16:36:54 +00:00
func HandleMessage(s xmpp.Sender, p stanza.Packet) {
msg, ok := p.(stanza.Message)
if !ok {
logPacketType(p)
2019-10-22 16:36:54 +00:00
return
}
2019-11-24 17:10:29 +00:00
component, ok := s.(*xmpp.Component)
if !ok {
log.Error("Not a component")
return
}
if msg.Type != "error" && msg.Body != "" {
log.WithFields(log.Fields{
"from": msg.From,
"to": msg.To,
}).Warn("Message")
log.Debugf("%#v", msg)
fromJid, err := stanza.NewJid(msg.From)
2019-11-24 17:10:29 +00:00
if err != nil {
log.Error("Invalid from JID!")
return
}
session, ok := sessions[fromJid.Bare()]
if !ok {
log.Error("Message from stranger")
return
}
toParts := strings.Split(msg.To, "@")
toID := toParts[0]
if len(toParts) > 1 {
2019-12-03 16:48:41 +00:00
toIDInt, err := strconv.ParseInt(toID, 10, 64)
2019-12-03 00:32:53 +00:00
if err == nil {
session.ProcessOutgoingMessage(toIDInt, msg.Body, 0, msg.From)
2019-11-24 17:10:29 +00:00
return
}
2019-12-03 00:32:53 +00:00
log.WithFields(log.Fields{
"toID": toID,
}).Error(errors.Wrap(err, "Invalid to JID!"))
2019-11-24 17:10:29 +00:00
} else if toID == gateway.Jid.Bare() {
2019-12-03 00:32:53 +00:00
if strings.HasPrefix(msg.Body, "/") {
response := session.ProcessTransportCommand(msg.Body)
2019-11-24 17:10:29 +00:00
if response != "" {
gateway.SendMessage(msg.From, "", response, component)
}
return
}
}
log.Warn("Unknown purpose of the message, skipping")
}
2019-10-22 16:36:54 +00:00
}
// HandlePresence processes an incoming XMPP presence
func HandlePresence(s xmpp.Sender, p stanza.Packet) {
prs, ok := p.(stanza.Presence)
if !ok {
logPacketType(p)
return
}
if prs.Type == "subscribe" {
handleSubscription(s, prs)
}
2019-11-24 17:10:29 +00:00
if prs.To == gateway.Jid.Bare() {
handlePresence(s, prs)
}
}
func handleSubscription(s xmpp.Sender, p stanza.Presence) {
log.WithFields(log.Fields{
"from": p.From,
"to": p.To,
}).Warn("Subscription request")
log.Debugf("%#v", p)
reply := stanza.Presence{Attrs: stanza.Attrs{
From: p.To,
To: p.From,
Id: p.Id,
Type: "subscribed",
}}
component, ok := s.(*xmpp.Component)
if !ok {
log.Error("Not a component")
return
}
_ = gateway.ResumableSend(component, reply)
}
func handlePresence(s xmpp.Sender, p stanza.Presence) {
presenceType := p.Type
if presenceType == "" {
presenceType = "online"
}
2019-11-24 17:10:29 +00:00
component, ok := s.(*xmpp.Component)
if !ok {
log.Error("Not a component")
return
}
log.WithFields(log.Fields{
"type": presenceType,
"from": p.From,
"to": p.To,
}).Warn("Presence")
log.Debugf("%#v", p)
// create session
fromJid, err := stanza.NewJid(p.From)
if err != nil {
log.Error("Invalid from JID!")
return
}
bareFromJid := fromJid.Bare()
2019-11-24 17:10:29 +00:00
session, ok := getTelegramInstance(bareFromJid, &persistence.Session{}, component)
if !ok {
return
}
switch p.Type {
// destroy session
case "unsubscribed", "unsubscribe":
session.Disconnect()
delete(sessions, bareFromJid)
// go offline
case "unavailable", "error":
session.Disconnect()
// go online
case "probe", "", "online":
// due to the weird implementation of go-tdlib wrapper, it won't
// return the client instance until successful authorization
go func() {
err = session.Connect()
if err != nil {
log.Error(errors.Wrap(err, "TDlib connection failure"))
2020-01-05 13:03:10 +00:00
} else {
for status := range session.StatusesRange() {
go session.ProcessStatusUpdate(
status.ID,
status.XMPP,
status.Description,
gateway.SPImmed(false),
)
}
}
}()
}
}
2019-12-19 20:58:20 +00:00
func handleGetVcardTempIq(s xmpp.Sender, iq *stanza.IQ) {
2019-12-19 20:58:20 +00:00
log.WithFields(log.Fields{
"from": iq.From,
"to": iq.To,
}).Warn("VCard request")
fromJid, err := stanza.NewJid(iq.From)
2019-12-19 20:58:20 +00:00
if err != nil {
log.Error("Invalid from JID!")
return
}
session, ok := sessions[fromJid.Bare()]
if !ok {
log.Error("IQ from stranger")
return
}
toParts := strings.Split(iq.To, "@")
toID, err := strconv.ParseInt(toParts[0], 10, 64)
if err != nil {
log.Error("Invalid IQ to")
return
}
chat, user, err := session.GetContactByID(toID, nil)
if err != nil {
log.Error(err)
return
}
vcard := extensions.IqVcardTemp{}
if chat != nil {
vcard.Fn.Text = chat.Title
if chat.Photo != nil {
path := chat.Photo.Small.Local.Path
file, err := os.Open(path)
if err == nil {
defer file.Close()
buf := new(bytes.Buffer)
binval := base64.NewEncoder(base64.StdEncoding, buf)
_, err = io.Copy(binval, file)
if err == nil {
vcard.Photo.Type.Text = "image/jpeg"
vcard.Photo.Binval.Text = buf.String()
} else {
log.Errorf("Error calculating hash: %v", path)
}
} else if path != "" {
log.Errorf("Photo does not exist: %v", path)
}
}
}
if user != nil {
vcard.Nickname.Text = user.Username
vcard.N.Given.Text = user.FirstName
vcard.N.Family.Text = user.LastName
vcard.Tel.Number.Text = user.PhoneNumber
}
answer := stanza.IQ{
Attrs: stanza.Attrs{
From: iq.To,
To: iq.From,
Id: iq.Id,
Type: "result",
},
Payload: vcard,
}
log.Debugf("%#v", answer)
component, ok := s.(*xmpp.Component)
if !ok {
log.Error("Not a component")
return
}
_ = gateway.ResumableSend(component, &answer)
2019-12-19 20:58:20 +00:00
}