diff options
Diffstat (limited to 'xmpp/gateway/gateway.go')
-rw-r--r-- | xmpp/gateway/gateway.go | 128 |
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 +} |