From 538b9bca8bb5ce6c6e8cbbbbf09530f804d05019 Mon Sep 17 00:00:00 2001 From: Bohdan Horbeshko Date: Sat, 17 May 2025 01:17:08 -0400 Subject: [PATCH] Add XEP-0359 IDs --- telegram/handlers.go | 8 ++++++- telegram/utils.go | 17 +++++++++----- xmpp/extensions/extensions.go | 25 +++++++++++++++++++++ xmpp/gateway/gateway.go | 42 ++++++++++++++++++++++++----------- xmpp/handlers.go | 6 ++++- 5 files changed, 78 insertions(+), 20 deletions(-) diff --git a/telegram/handlers.go b/telegram/handlers.go index e317ecb..11c38ba 100644 --- a/telegram/handlers.go +++ b/telegram/handlers.go @@ -11,6 +11,7 @@ import ( "dev.narayana.im/narayana/telegabber/telegram/formatter" "dev.narayana.im/narayana/telegabber/xmpp/gateway" + "github.com/google/uuid" log "github.com/sirupsen/logrus" "github.com/zelenin/go-tdlib/client" ) @@ -393,8 +394,13 @@ func (c *Client) updateMessageContent(update *client.UpdateMessageContent) { } else { from = gateway.CHATNODE(update.ChatId) } + id := "e"+sId + uuid, err := uuid.NewRandom() + if err == nil { + id = id+":"+uuid.String() + } for _, jid := range jids { - gateway.SendMessage(jid, from, text.String(), "e"+sId, c.xmpp, nil, 0, replaceId, isCarbon, isMUC, false, originalFrom) + gateway.SendMessage(jid, from, text.String(), id, c.xmpp, nil, 0, replaceId, isCarbon, isMUC, false, originalFrom, "") } } } diff --git a/telegram/utils.go b/telegram/utils.go index d32d69d..a902a76 100644 --- a/telegram/utils.go +++ b/telegram/utils.go @@ -1644,10 +1644,14 @@ func (c *Client) SendMessageToGateway(chatId int64, message *client.Message, id // forward message to XMPP var sId string + var stanzaId string + strId := strconv.FormatInt(message.Id, 10) if id == "" { - sId = strconv.FormatInt(message.Id, 10) + sId = strId + stanzaId = strId } else { sId = id + stanzaId = strId } var from string @@ -1663,9 +1667,9 @@ func (c *Client) SendMessageToGateway(chatId int64, message *client.Message, id } for _, jid := range jids { - gateway.SendMessageWithOOB(jid, from, text, sId, c.xmpp, reply, timestamp, oob, "", isCarbon, isGroupchat, c.Session.Receipts, originalFrom) + gateway.SendMessageWithOOB(jid, from, text, sId, c.xmpp, reply, timestamp, oob, "", isCarbon, isGroupchat, c.Session.Receipts, originalFrom, stanzaId) if auxText != "" { - gateway.SendMessage(jid, from, auxText, sId, c.xmpp, reply, timestamp, "", isCarbon, isGroupchat, c.Session.Receipts, originalFrom) + gateway.SendMessage(jid, from, auxText, sId, c.xmpp, reply, timestamp, "", isCarbon, isGroupchat, c.Session.Receipts, originalFrom, stanzaId) } } c.UpdateLastChatMessageId(chatId, sId) @@ -2353,11 +2357,12 @@ func (c *Client) sendMessagesReverse(chatID int64, messages []*client.Message, p if plain { reply, _ := c.getMessageReply(message, false, true) + sId := strconv.FormatInt(message.Id, 10) gateway.SendMessage( c.jid, sChatId, c.formatMessage(0, 0, false, message), - strconv.FormatInt(message.Id, 10), + sId, c.xmpp, reply, 0, @@ -2366,12 +2371,14 @@ func (c *Client) sendMessagesReverse(chatID int64, messages []*client.Message, p false, false, "", + "", ) } else { + msgId, _ := gateway.IdsDB.GetByTgIds(c.Session.Login, c.jid, chatID, message.Id) c.SendMessageToGateway( chatID, message, - "", + msgId, true, mucJid + "/" + c.GetMUCNickname(c.getMessageSenderId(message)), []string{toJid}, diff --git a/xmpp/extensions/extensions.go b/xmpp/extensions/extensions.go index 2afc36c..2886e23 100644 --- a/xmpp/extensions/extensions.go +++ b/xmpp/extensions/extensions.go @@ -289,6 +289,19 @@ type MessageAddress struct { Jid string `xml:"jid,attr"` } +// MessageStanzaId is from XEP-0359 +type MessageStanzaId struct { + XMLName xml.Name `xml:"urn:xmpp:sid:0 stanza-id"` + Id string `xml:"id,attr"` + By string `xml:"by,attr"` +} + +// MessageOriginId is from XEP-0359 +type MessageOriginId struct { + XMLName xml.Name `xml:"urn:xmpp:sid:0 origin-id"` + Id string `xml:"id,attr"` +} + // EmptySubject is a dummy for MUCs to circumvent omitempty. Not registered as it would conflict with Subject field type EmptySubject struct { XMLName xml.Name `xml:"subject"` @@ -488,4 +501,16 @@ func init() { "http://jabber.org/protocol/address", "addresses", }, MessageAddresses{}) + + // stable stanza id + stanza.TypeRegistry.MapExtension(stanza.PKTMessage, xml.Name{ + "urn:xmpp:sid:0", + "stanza-id", + }, MessageStanzaId{}) + + // message addresses + stanza.TypeRegistry.MapExtension(stanza.PKTMessage, xml.Name{ + "urn:xmpp:sid:0", + "origin-id", + }, MessageOriginId{}) } diff --git a/xmpp/gateway/gateway.go b/xmpp/gateway/gateway.go index 255fd76..2bddf83 100644 --- a/xmpp/gateway/gateway.go +++ b/xmpp/gateway/gateway.go @@ -88,8 +88,8 @@ func MUCJID(chatId int64) string { } // SendMessage creates and sends a message stanza -func SendMessage(to, from, body, id string, component *xmpp.Component, reply *Reply, timestamp int64, replaceId string, isCarbon, isGroupchat, requestReceipt bool, originalFrom string) { - sendMessageWrapper(to, from, body, "", "", id, component, reply, nil, timestamp, "", replaceId, isCarbon, isGroupchat, false, requestReceipt, originalFrom, 0, "") +func SendMessage(to, from, body, id string, component *xmpp.Component, reply *Reply, timestamp int64, replaceId string, isCarbon, isGroupchat, requestReceipt bool, originalFrom, stanzaId string) { + sendMessageWrapper(to, from, body, "", "", id, component, reply, nil, timestamp, "", replaceId, isCarbon, isGroupchat, false, requestReceipt, originalFrom, 0, "", stanzaId) } // SendServiceMessage creates and sends a simple message stanza from transport @@ -98,7 +98,7 @@ func SendServiceMessage(to, body string, component *xmpp.Component) { if uuid, err := uuid.NewRandom(); err == nil { id = uuid.String() } - sendMessageWrapper(to, "", body, "", "", id, component, nil, nil, 0, "", "", false, false, false, false, "", 0, "") + sendMessageWrapper(to, "", body, "", "", id, component, nil, nil, 0, "", "", false, false, false, false, "", 0, "", "") } // SendTextMessage creates and sends a simple message stanza @@ -107,27 +107,27 @@ func SendTextMessage(to, from, body string, component *xmpp.Component, isGroupch if uuid, err := uuid.NewRandom(); err == nil { id = uuid.String() } - sendMessageWrapper(to, from, body, "", "", id, component, nil, nil, 0, "", "", false, isGroupchat, false, false, "", 0, "") + sendMessageWrapper(to, from, body, "", "", id, component, nil, nil, 0, "", "", false, isGroupchat, false, false, "", 0, "", "") } // SendErrorMessage creates and sends an error message stanza func SendErrorMessage(to, from, text string, code int, isGroupchat bool, component *xmpp.Component) { - sendMessageWrapper(to, from, "", "", text, "", component, nil, nil, 0, "", "", false, isGroupchat, false, false, "", code, "") + sendMessageWrapper(to, from, "", "", text, "", component, nil, nil, 0, "", "", false, isGroupchat, false, false, "", code, "", "") } // SendErrorMessageWithBody creates and sends an error message stanza with body payload func SendErrorMessageWithBody(to, from, body, errorText, id string, code int, isGroupchat bool, component *xmpp.Component) { - sendMessageWrapper(to, from, body, "", errorText, id, component, nil, nil, 0, "", "", false, isGroupchat, false, false, "", code, "") + sendMessageWrapper(to, from, body, "", errorText, id, component, nil, nil, 0, "", "", false, isGroupchat, false, false, "", code, "", "") } // SendMessageWithOOB creates and sends a message stanza with OOB URL -func SendMessageWithOOB(to, from, body, id string, component *xmpp.Component, reply *Reply, timestamp int64, oob, replaceId string, isCarbon, isGroupchat, requestReceipt bool, originalFrom string) { - sendMessageWrapper(to, from, body, "", "", id, component, reply, nil, timestamp, oob, replaceId, isCarbon, isGroupchat, false, requestReceipt, originalFrom, 0, "") +func SendMessageWithOOB(to, from, body, id string, component *xmpp.Component, reply *Reply, timestamp int64, oob, replaceId string, isCarbon, isGroupchat, requestReceipt bool, originalFrom, stanzaId string) { + sendMessageWrapper(to, from, body, "", "", id, component, reply, nil, timestamp, oob, replaceId, isCarbon, isGroupchat, false, requestReceipt, originalFrom, 0, "", stanzaId) } // SendSubjectMessage creates and sends a MUC subject func SendSubjectMessage(to, from, subject, id string, component *xmpp.Component, timestamp int64) { - sendMessageWrapper(to, from, "", subject, "", id, component, nil, nil, timestamp, "", "", false, true, true, false, "", 0, "") + sendMessageWrapper(to, from, "", subject, "", id, component, nil, nil, timestamp, "", "", false, true, true, false, "", 0, "", "") } // SendMessageMarker creates and sends a message stanza with a XEP-0333 marker @@ -135,15 +135,15 @@ func SendMessageMarker(to string, from string, component *xmpp.Component, marker sendMessageWrapper(to, from, "", "", "", "", component, nil, &marker{ Type: markerType, Id: markerId, - }, 0, "", "", false, false, false, false, "", 0, "") + }, 0, "", "", false, false, false, false, "", 0, "", "") } // SendMUCInvite creates and send a MUC invitation message func SendMUCInvite(to string, from string, component *xmpp.Component, inviteFrom string) { - sendMessageWrapper(to, from, "", "", "", "", component, nil, nil, 0, "", "", false, false, false, false, "", 0, inviteFrom) + sendMessageWrapper(to, from, "", "", "", "", component, nil, nil, 0, "", "", false, false, false, false, "", 0, inviteFrom, "") } -func sendMessageWrapper(to, from, body, subject, errorText, id string, component *xmpp.Component, reply *Reply, marker *marker, timestamp int64, oob, replaceId string, isCarbon, isGroupchat, forceSubject, requestReceipt bool, originalFrom string, errorCode int, inviteFrom string) { +func sendMessageWrapper(to, from, body, subject, errorText, id string, component *xmpp.Component, reply *Reply, marker *marker, timestamp int64, oob, replaceId string, isCarbon, isGroupchat, forceSubject, requestReceipt bool, originalFrom string, errorCode int, inviteFrom, stanzaId string) { toJid, err := stanza.NewJid(to) if err != nil { log.WithFields(log.Fields{ @@ -158,19 +158,24 @@ func sendMessageWrapper(to, from, body, subject, errorText, id string, component var logFrom string var messageFrom string var messageTo string + var bareFrom string if isGroupchat { logFrom = from messageFrom = from + bareFrom, _, _ = SplitJID(from) } else { if from == "" { logFrom = componentJid messageFrom = componentJid + bareFrom = componentJid } else if inviteFrom != "" { logFrom = from messageFrom = from + "@" + Jid.Bare() + bareFrom = messageFrom } else { logFrom = from messageFrom = from + "@" + componentJid + bareFrom = from + "@" + Jid.Bare() } } if isCarbon { @@ -254,7 +259,7 @@ func sendMessageWrapper(to, from, body, subject, errorText, id string, component if timestamp != 0 { var delayFrom string if isGroupchat { - delayFrom, _, _ = SplitJID(from) + delayFrom = bareFrom } message.Extensions = append(message.Extensions, extensions.MessageDelay{ From: delayFrom, @@ -301,6 +306,17 @@ func sendMessageWrapper(to, from, body, subject, errorText, id string, component Jid: messageFrom, }) } + if stanzaId != "" { + message.Extensions = append(message.Extensions, extensions.MessageStanzaId{ + Id: stanzaId, + By: bareFrom, + }) + if stanzaId != id { + message.Extensions = append(message.Extensions, extensions.MessageOriginId{ + Id: id, + }) + } + } if isCarbon { carbonMessage := extensions.ClientMessage{ diff --git a/xmpp/handlers.go b/xmpp/handlers.go index 7a499e7..fa32087 100644 --- a/xmpp/handlers.go +++ b/xmpp/handlers.go @@ -181,7 +181,10 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) { } else { id := reply.Id if id[0] == 'e' { - id = id[1:] + idParts := strings.Split(id[1:], ":") + if len(idParts) >= 1 { + id = idParts[0] + } } replyId, err = strconv.ParseInt(id, 10, 64) if err != nil { @@ -848,6 +851,7 @@ func handleGetDiscoInfo(s xmpp.Sender, iq *stanza.IQ, di *stanza.DiscoInfo) { "muc_unsecured", "http://jabber.org/protocol/muc#stable_id", "jabber:iq:register", + "urn:xmpp:sid:0", ) fields := []*stanza.Field{ &stanza.Field{