From 42ed16bf9e9d72bf226045f1f291b9d58e2a6200 Mon Sep 17 00:00:00 2001
From: Bohdan Horbeshko <bodqhrohro@gmail.com>
Date: Sat, 18 Mar 2023 17:43:11 -0400
Subject: Simulate carbons

---
 xmpp/gateway/gateway.go | 77 +++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 68 insertions(+), 9 deletions(-)

(limited to 'xmpp/gateway')

diff --git a/xmpp/gateway/gateway.go b/xmpp/gateway/gateway.go
index de8b495..534ee7e 100644
--- a/xmpp/gateway/gateway.go
+++ b/xmpp/gateway/gateway.go
@@ -2,6 +2,7 @@ package gateway
 
 import (
 	"encoding/xml"
+	"github.com/pkg/errors"
 	"strings"
 	"sync"
 
@@ -33,31 +34,44 @@ var Jid *stanza.Jid
 // were changed and need to be re-flushed to the YamlDB
 var DirtySessions = false
 
+// MessageOutgoingPermission allows to fake outgoing messages by foreign JIDs
+var MessageOutgoingPermission = false
+
 // SendMessage creates and sends a message stanza
-func SendMessage(to string, from string, body string, id string, component *xmpp.Component, reply *Reply) {
-	sendMessageWrapper(to, from, body, id, component, reply, "")
+func SendMessage(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, isOutgoing bool) {
+	sendMessageWrapper(to, from, body, id, component, reply, "", isOutgoing)
 }
 
 // SendServiceMessage creates and sends a simple message stanza from transport
 func SendServiceMessage(to string, body string, component *xmpp.Component) {
-	sendMessageWrapper(to, "", body, "", component, nil, "")
+	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, "")
+	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) {
-	sendMessageWrapper(to, from, body, id, component, reply, oob)
+func SendMessageWithOOB(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, oob string, isOutgoing bool) {
+	sendMessageWrapper(to, from, body, id, component, reply, oob, isOutgoing)
 }
 
-func sendMessageWrapper(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, oob string) {
+func sendMessageWrapper(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, oob string, isOutgoing 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
@@ -65,6 +79,12 @@ func sendMessageWrapper(to string, from string, body string, id string, componen
 		logFrom = from
 		messageFrom = from + "@" + componentJid
 	}
+	if isOutgoing {
+		messageTo = messageFrom
+		messageFrom = bareTo + "/" + Jid.Resource
+	} else {
+		messageTo = to
+	}
 
 	log.WithFields(log.Fields{
 		"from": logFrom,
@@ -74,7 +94,7 @@ func sendMessageWrapper(to string, from string, body string, id string, componen
 	message := stanza.Message{
 		Attrs: stanza.Attrs{
 			From: messageFrom,
-			To:   to,
+			To:   messageTo,
 			Type: "chat",
 			Id:   id,
 		},
@@ -96,7 +116,34 @@ func sendMessageWrapper(to string, from string, body string, id string, componen
 		}
 	}
 
-	sendMessage(&message, component)
+	if isOutgoing {
+		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,
+			},
+		}
+		privilegeMessage.Extensions = append(privilegeMessage.Extensions, extensions.ComponentPrivilege{
+			Forwarded: stanza.Forwarded{
+				Stanza: carbonMessage,
+			},
+		})
+		sendMessage(&privilegeMessage, component)
+	} else {
+		sendMessage(&message, component)
+	}
 }
 
 // SetNickname sets a new nickname for a contact
@@ -297,3 +344,15 @@ func ResumableSend(component *xmpp.Component, packet stanza.Packet) error {
 	}
 	return err
 }
+
+// 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
+}
-- 
cgit v1.2.3