aboutsummaryrefslogtreecommitdiff
path: root/xmpp/gateway/gateway.go
diff options
context:
space:
mode:
Diffstat (limited to 'xmpp/gateway/gateway.go')
-rw-r--r--xmpp/gateway/gateway.go128
1 files changed, 125 insertions, 3 deletions
diff --git a/xmpp/gateway/gateway.go b/xmpp/gateway/gateway.go
index d4620e6..dfe2ebf 100644
--- a/xmpp/gateway/gateway.go
+++ b/xmpp/gateway/gateway.go
@@ -2,9 +2,11 @@ package gateway
import (
"encoding/xml"
+ "github.com/pkg/errors"
"strings"
"sync"
+ "dev.narayana.im/narayana/telegabber/badger"
"dev.narayana.im/narayana/telegabber/xmpp/extensions"
log "github.com/sirupsen/logrus"
@@ -13,6 +15,13 @@ import (
"gosrc.io/xmpp/stanza"
)
+type Reply struct {
+ Author string
+ Id string
+ Start uint64
+ End uint64
+}
+
const NSNick string = "http://jabber.org/protocol/nick"
// Queue stores presences to send later
@@ -22,16 +31,51 @@ var QueueLock = sync.Mutex{}
// Jid stores the component's JID object
var Jid *stanza.Jid
+// IdsDB provides a disk-backed bidirectional dictionary of Telegram and XMPP ids
+var IdsDB badger.IdsDB
+
// DirtySessions denotes that some Telegram session configurations
// were changed and need to be re-flushed to the YamlDB
var DirtySessions = false
+// MessageOutgoingPermissionVersion contains a XEP-0356 version to fake outgoing messages by foreign JIDs
+var MessageOutgoingPermissionVersion = 0
+
// SendMessage creates and sends a message stanza
-func SendMessage(to string, from string, body string, component *xmpp.Component) {
+func SendMessage(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, isCarbon bool) {
+ sendMessageWrapper(to, from, body, id, component, reply, "", isCarbon)
+}
+
+// SendServiceMessage creates and sends a simple message stanza from transport
+func SendServiceMessage(to string, body string, component *xmpp.Component) {
+ sendMessageWrapper(to, "", body, "", component, nil, "", false)
+}
+
+// SendTextMessage creates and sends a simple message stanza
+func SendTextMessage(to string, from string, body string, component *xmpp.Component) {
+ sendMessageWrapper(to, from, body, "", component, nil, "", false)
+}
+
+// SendMessageWithOOB creates and sends a message stanza with OOB URL
+func SendMessageWithOOB(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, oob string, isCarbon bool) {
+ sendMessageWrapper(to, from, body, id, component, reply, oob, isCarbon)
+}
+
+func sendMessageWrapper(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, oob string, isCarbon bool) {
+ toJid, err := stanza.NewJid(to)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "to": to,
+ }).Error(errors.Wrap(err, "Invalid to JID!"))
+ return
+ }
+ bareTo := toJid.Bare()
+
componentJid := Jid.Full()
var logFrom string
var messageFrom string
+ var messageTo string
if from == "" {
logFrom = componentJid
messageFrom = componentJid
@@ -39,6 +83,12 @@ func SendMessage(to string, from string, body string, component *xmpp.Component)
logFrom = from
messageFrom = from + "@" + componentJid
}
+ if isCarbon {
+ messageTo = messageFrom
+ messageFrom = bareTo + "/" + Jid.Resource
+ } else {
+ messageTo = to
+ }
log.WithFields(log.Fields{
"from": logFrom,
@@ -48,13 +98,67 @@ func SendMessage(to string, from string, body string, component *xmpp.Component)
message := stanza.Message{
Attrs: stanza.Attrs{
From: messageFrom,
- To: to,
+ To: messageTo,
Type: "chat",
+ Id: id,
},
Body: body,
}
- sendMessage(&message, component)
+ if oob != "" {
+ message.Extensions = append(message.Extensions, stanza.OOB{
+ URL: oob,
+ })
+ }
+ if reply != nil {
+ message.Extensions = append(message.Extensions, extensions.Reply{
+ To: reply.Author,
+ Id: reply.Id,
+ })
+ if reply.End > 0 {
+ message.Extensions = append(message.Extensions, extensions.NewReplyFallback(reply.Start, reply.End))
+ }
+ }
+ if !isCarbon && toJid.Resource != "" {
+ message.Extensions = append(message.Extensions, stanza.HintNoCopy{})
+ }
+
+ if isCarbon {
+ carbonMessage := extensions.ClientMessage{
+ Attrs: stanza.Attrs{
+ From: bareTo,
+ To: to,
+ Type: "chat",
+ },
+ }
+ carbonMessage.Extensions = append(carbonMessage.Extensions, extensions.CarbonSent{
+ Forwarded: stanza.Forwarded{
+ Stanza: extensions.ClientMessage(message),
+ },
+ })
+ privilegeMessage := stanza.Message{
+ Attrs: stanza.Attrs{
+ From: Jid.Bare(),
+ To: toJid.Domain,
+ },
+ }
+ if MessageOutgoingPermissionVersion == 2 {
+ privilegeMessage.Extensions = append(privilegeMessage.Extensions, extensions.ComponentPrivilege2{
+ Forwarded: stanza.Forwarded{
+ Stanza: carbonMessage,
+ },
+ })
+ } else {
+ privilegeMessage.Extensions = append(privilegeMessage.Extensions, extensions.ComponentPrivilege1{
+ Forwarded: stanza.Forwarded{
+ Stanza: carbonMessage,
+ },
+ })
+ }
+ sendMessage(&privilegeMessage, component)
+ } else {
+ sendMessage(&message, component)
+ }
}
// SetNickname sets a new nickname for a contact
@@ -255,3 +359,21 @@ func ResumableSend(component *xmpp.Component, packet stanza.Packet) error {
}
return err
}
+
+// SubscribeToTransport ensures a two-way subscription to the transport
+func SubscribeToTransport(component *xmpp.Component, jid string) {
+ SendPresence(component, jid, SPType("subscribe"))
+ SendPresence(component, jid, SPType("subscribed"))
+}
+
+// SplitJID tokenizes a JID string to bare JID and resource
+func SplitJID(from string) (string, string, bool) {
+ fromJid, err := stanza.NewJid(from)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "from": from,
+ }).Error(errors.Wrap(err, "Invalid from JID!"))
+ return "", "", false
+ }
+ return fromJid.Bare(), fromJid.Resource, true
+}