From 608f67551297a14e2e23603413bbce66f6ad5cd9 Mon Sep 17 00:00:00 2001 From: Bohdan Horbeshko Date: Wed, 2 Aug 2023 16:41:18 -0400 Subject: [PATCH 1/4] Revert sending carbons for outgoing messages to other resources (they duplicate what clients already send to each other) --- Makefile | 2 +- telegabber.go | 2 +- telegram/commands.go | 2 +- telegram/handlers.go | 19 ++++++++----------- telegram/utils.go | 11 +++-------- xmpp/handlers.go | 1 - 6 files changed, 14 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 2eb17ac..6732740 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ COMMIT := $(shell git rev-parse --short HEAD) TD_COMMIT := "8517026415e75a8eec567774072cbbbbb52376c1" -VERSION := "v1.7.2" +VERSION := "v1.7.3" MAKEOPTS := "-j4" all: diff --git a/telegabber.go b/telegabber.go index 9ce070f..3d7d2ea 100644 --- a/telegabber.go +++ b/telegabber.go @@ -15,7 +15,7 @@ import ( goxmpp "gosrc.io/xmpp" ) -var version string = "1.7.2" +var version string = "1.7.3" var commit string var sm *goxmpp.StreamManager diff --git a/telegram/commands.go b/telegram/commands.go index e164ce1..206e049 100644 --- a/telegram/commands.go +++ b/telegram/commands.go @@ -658,7 +658,7 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool) } if messages != nil && messages.Messages != nil { for _, message := range messages.Messages { - c.ProcessIncomingMessage(targetChatId, message, "") + c.ProcessIncomingMessage(targetChatId, message) } } // print vCard diff --git a/telegram/handlers.go b/telegram/handlers.go index cedea63..0d1cda9 100644 --- a/telegram/handlers.go +++ b/telegram/handlers.go @@ -205,27 +205,24 @@ func (c *Client) updateChatLastMessage(update *client.UpdateChatLastMessage) { func (c *Client) updateNewMessage(update *client.UpdateNewMessage) { chatId := update.Message.ChatId - c.SendMessageLock.Lock() - c.SendMessageLock.Unlock() - xmppId, err := gateway.IdsDB.GetByTgIds(c.Session.Login, c.jid, chatId, update.Message.Id) - var ignoredResource string - if err == nil { - ignoredResource = c.popFromOutbox(xmppId) - } else { - log.Infof("Couldn't retrieve XMPP message ids for %v, an echo may happen", update.Message.Id) - } - // guarantee sequential message delivering per chat lock := c.getChatMessageLock(chatId) go func() { lock.Lock() defer lock.Unlock() + // ignore self outgoing messages + if update.Message.IsOutgoing && + update.Message.SendingState != nil && + update.Message.SendingState.MessageSendingStateType() == client.TypeMessageSendingStatePending { + return + } + log.WithFields(log.Fields{ "chat_id": chatId, }).Warn("New message from chat") - c.ProcessIncomingMessage(chatId, update.Message, ignoredResource) + c.ProcessIncomingMessage(chatId, update.Message) c.updateLastMessageHash(update.Message.ChatId, update.Message.Id, update.Message.Content) }() diff --git a/telegram/utils.go b/telegram/utils.go index cd25c22..62ce945 100644 --- a/telegram/utils.go +++ b/telegram/utils.go @@ -911,7 +911,7 @@ func (c *Client) ensureDownloadFile(file *client.File) *client.File { } // ProcessIncomingMessage transfers a message to XMPP side and marks it as read on Telegram side -func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message, ignoredResource string) { +func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) { var isPM bool var err error if gateway.MessageOutgoingPermission && c.Session.Carbons { @@ -921,13 +921,8 @@ func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message, i } } - isOutgoing := message.IsOutgoing - isCarbon := isPM && isOutgoing - jids := c.getCarbonFullJids(isOutgoing, ignoredResource) - if len(jids) == 0 { - log.Info("The only resource is ignored, aborting") - return - } + isCarbon := isPM && message.IsOutgoing + jids := c.getCarbonFullJids(isCarbon, "") var text, oob, auxText string diff --git a/xmpp/handlers.go b/xmpp/handlers.go index fd1afad..4e3354e 100644 --- a/xmpp/handlers.go +++ b/xmpp/handlers.go @@ -183,7 +183,6 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) { if err != nil { log.Errorf("Failed to save ids %v/%v %v", toID, tgMessageId, msg.Id) } - session.AddToOutbox(msg.Id, resource) } } else { /* From c03ccfdfb713d4fcb089600d9fd91f03e469daca Mon Sep 17 00:00:00 2001 From: Bohdan Horbeshko Date: Wed, 2 Aug 2023 17:08:06 -0400 Subject: [PATCH 2/4] Support urn:xmpp:privilege:2 --- Makefile | 2 +- telegabber.go | 2 +- telegram/commands.go | 2 +- telegram/utils.go | 4 ++-- xmpp/extensions/extensions.go | 26 ++++++++++++++++++++++---- xmpp/gateway/gateway.go | 22 +++++++++++++++------- xmpp/handlers.go | 21 ++++++++++++++++----- 7 files changed, 58 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index 6732740..7857e17 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ COMMIT := $(shell git rev-parse --short HEAD) TD_COMMIT := "8517026415e75a8eec567774072cbbbbb52376c1" -VERSION := "v1.7.3" +VERSION := "v1.7.4" MAKEOPTS := "-j4" all: diff --git a/telegabber.go b/telegabber.go index 3d7d2ea..df13dd6 100644 --- a/telegabber.go +++ b/telegabber.go @@ -15,7 +15,7 @@ import ( goxmpp "gosrc.io/xmpp" ) -var version string = "1.7.3" +var version string = "1.7.4" var commit string var sm *goxmpp.StreamManager diff --git a/telegram/commands.go b/telegram/commands.go index 206e049..0c83945 100644 --- a/telegram/commands.go +++ b/telegram/commands.go @@ -384,7 +384,7 @@ func (c *Client) ProcessTransportCommand(cmdline string, resource string) string } case "config": if len(args) > 1 { - if !gateway.MessageOutgoingPermission && args[0] == "carbons" && args[1] == "true" { + if gateway.MessageOutgoingPermissionVersion == 0 && args[0] == "carbons" && args[1] == "true" { return "The server did not allow to enable carbons" } diff --git a/telegram/utils.go b/telegram/utils.go index 62ce945..4caf88c 100644 --- a/telegram/utils.go +++ b/telegram/utils.go @@ -842,7 +842,7 @@ func (c *Client) messageToPrefix(message *client.Message, previewString string, prefix := []string{} // message direction var directionChar string - if !isPM || !gateway.MessageOutgoingPermission || !c.Session.Carbons { + if !isPM || gateway.MessageOutgoingPermissionVersion == 0 || !c.Session.Carbons { if c.Session.AsciiArrows { if message.IsOutgoing { directionChar = "> " @@ -914,7 +914,7 @@ func (c *Client) ensureDownloadFile(file *client.File) *client.File { func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) { var isPM bool var err error - if gateway.MessageOutgoingPermission && c.Session.Carbons { + if gateway.MessageOutgoingPermissionVersion > 0 && c.Session.Carbons { isPM, err = c.IsPM(chatId) if err != nil { log.Errorf("Could not determine if chat is PM: %v", err) diff --git a/xmpp/extensions/extensions.go b/xmpp/extensions/extensions.go index 2d547af..192b630 100644 --- a/xmpp/extensions/extensions.go +++ b/xmpp/extensions/extensions.go @@ -154,12 +154,19 @@ type CarbonSent struct { } // ComponentPrivilege is from XEP-0356 -type ComponentPrivilege struct { +type ComponentPrivilege1 struct { XMLName xml.Name `xml:"urn:xmpp:privilege:1 privilege"` Perms []ComponentPerm `xml:"perm"` Forwarded stanza.Forwarded `xml:"urn:xmpp:forward:0 forwarded"` } +// ComponentPrivilege is from XEP-0356 +type ComponentPrivilege2 struct { + XMLName xml.Name `xml:"urn:xmpp:privilege:2 privilege"` + Perms []ComponentPerm `xml:"perm"` + Forwarded stanza.Forwarded `xml:"urn:xmpp:forward:0 forwarded"` +} + // ComponentPerm is from XEP-0356 type ComponentPerm struct { XMLName xml.Name `xml:"perm"` @@ -227,7 +234,12 @@ func (c CarbonSent) Namespace() string { } // Namespace is a namespace! -func (c ComponentPrivilege) Namespace() string { +func (c ComponentPrivilege1) Namespace() string { + return c.XMLName.Space +} + +// Namespace is a namespace! +func (c ComponentPrivilege2) Namespace() string { return c.XMLName.Space } @@ -297,11 +309,17 @@ func init() { "sent", }, CarbonSent{}) - // component privilege + // component privilege v1 stanza.TypeRegistry.MapExtension(stanza.PKTMessage, xml.Name{ "urn:xmpp:privilege:1", "privilege", - }, ComponentPrivilege{}) + }, ComponentPrivilege1{}) + + // component privilege v2 + stanza.TypeRegistry.MapExtension(stanza.PKTMessage, xml.Name{ + "urn:xmpp:privilege:2", + "privilege", + }, ComponentPrivilege2{}) // message edit stanza.TypeRegistry.MapExtension(stanza.PKTMessage, xml.Name{ diff --git a/xmpp/gateway/gateway.go b/xmpp/gateway/gateway.go index 1be2fca..7a2500e 100644 --- a/xmpp/gateway/gateway.go +++ b/xmpp/gateway/gateway.go @@ -38,8 +38,8 @@ var IdsDB badger.IdsDB // 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 +// 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, id string, component *xmpp.Component, reply *Reply, isCarbon bool) { @@ -142,11 +142,19 @@ func sendMessageWrapper(to string, from string, body string, id string, componen To: toJid.Domain, }, } - privilegeMessage.Extensions = append(privilegeMessage.Extensions, extensions.ComponentPrivilege{ - Forwarded: stanza.Forwarded{ - Stanza: carbonMessage, - }, - }) + 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) diff --git a/xmpp/handlers.go b/xmpp/handlers.go index 4e3354e..6679a72 100644 --- a/xmpp/handlers.go +++ b/xmpp/handlers.go @@ -209,14 +209,25 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) { } if msg.Body == "" { - var privilege extensions.ComponentPrivilege - if ok := msg.Get(&privilege); ok { - log.Debugf("privilege: %#v", privilege) + var privilege1 extensions.ComponentPrivilege1 + if ok := msg.Get(&privilege1); ok { + log.Debugf("privilege1: %#v", privilege1) } - for _, perm := range privilege.Perms { + for _, perm := range privilege1.Perms { if perm.Access == "message" && perm.Type == "outgoing" { - gateway.MessageOutgoingPermission = true + gateway.MessageOutgoingPermissionVersion = 1 + } + } + + var privilege2 extensions.ComponentPrivilege2 + if ok := msg.Get(&privilege2); ok { + log.Debugf("privilege2: %#v", privilege2) + } + + for _, perm := range privilege2.Perms { + if perm.Access == "message" && perm.Type == "outgoing" { + gateway.MessageOutgoingPermissionVersion = 2 } } } From 9377d7a15538a6c0af97937806ecd55eb112beb3 Mon Sep 17 00:00:00 2001 From: Bohdan Horbeshko Date: Sun, 6 Aug 2023 20:04:49 -0400 Subject: [PATCH 3/4] Save/read unavailable presence type in cache --- Makefile | 2 +- telegabber.go | 2 +- telegram/cache/cache.go | 10 ++++++++++ telegram/utils.go | 40 ++++++++++++++++++++++++++++++++++++---- xmpp/handlers.go | 14 +++++++++++--- 5 files changed, 59 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 7857e17..33bedad 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ COMMIT := $(shell git rev-parse --short HEAD) TD_COMMIT := "8517026415e75a8eec567774072cbbbbb52376c1" -VERSION := "v1.7.4" +VERSION := "v1.7.5" MAKEOPTS := "-j4" all: diff --git a/telegabber.go b/telegabber.go index df13dd6..37d5890 100644 --- a/telegabber.go +++ b/telegabber.go @@ -15,7 +15,7 @@ import ( goxmpp "gosrc.io/xmpp" ) -var version string = "1.7.4" +var version string = "1.7.5" var commit string var sm *goxmpp.StreamManager diff --git a/telegram/cache/cache.go b/telegram/cache/cache.go index 3d9608d..6847d3e 100644 --- a/telegram/cache/cache.go +++ b/telegram/cache/cache.go @@ -133,3 +133,13 @@ func (cache *Cache) SetStatus(id int64, show string, status string) { Description: status, } } + +// Destruct splits a cached status into show, description and type +func (status *Status) Destruct() (show, description, typ string) { + show, description = status.XMPP, status.Description + if show == "unavailable" { + typ = show + show = "" + } + return +} diff --git a/telegram/utils.go b/telegram/utils.go index 4caf88c..2578671 100644 --- a/telegram/utils.go +++ b/telegram/utils.go @@ -243,15 +243,33 @@ func (c *Client) ProcessStatusUpdate(chatID int64, status string, show string, o cachedStatus, ok := c.cache.GetStatus(chatID) if status == "" { if ok { - show, status = cachedStatus.XMPP, cachedStatus.Description + var typ string + show, status, typ = cachedStatus.Destruct() + if presenceType == "" { + presenceType = typ + } + log.WithFields(log.Fields{ + "show": show, + "status": status, + "presenceType": presenceType, + }).Debug("Cached status") } else if user != nil && user.Status != nil { show, status, presenceType = c.userStatusToText(user.Status, chatID) + log.WithFields(log.Fields{ + "show": show, + "status": status, + "presenceType": presenceType, + }).Debug("Status to text") } else { show, status = "chat", chat.Title } } - c.cache.SetStatus(chatID, show, status) + cacheShow := show + if presenceType == "unavailable" { + cacheShow = presenceType + } + c.cache.SetStatus(chatID, cacheShow, status) newArgs := []args.V{ gateway.SPFrom(strconv.FormatInt(chatID, 10)), @@ -1366,12 +1384,26 @@ func (c *Client) UpdateChatNicknames() { for _, id := range c.cache.ChatsKeys() { chat, ok := c.cache.GetChat(id) if ok { + newArgs := []args.V{ + gateway.SPFrom(strconv.FormatInt(id, 10)), + gateway.SPNickname(chat.Title), + } + + cachedStatus, ok := c.cache.GetStatus(id) + if ok { + show, status, typ := cachedStatus.Destruct() + newArgs = append(newArgs, gateway.SPShow(show), gateway.SPStatus(status)) + if typ != "" { + newArgs = append(newArgs, gateway.SPType(typ)) + } + } + gateway.SendPresence( c.xmpp, c.jid, - gateway.SPFrom(strconv.FormatInt(id, 10)), - gateway.SPNickname(chat.Title), + newArgs..., ) + gateway.SetNickname(c.jid, strconv.FormatInt(id, 10), chat.Title, c.xmpp) } } diff --git a/xmpp/handlers.go b/xmpp/handlers.go index 6679a72..e85dfc9 100644 --- a/xmpp/handlers.go +++ b/xmpp/handlers.go @@ -15,6 +15,7 @@ import ( "dev.narayana.im/narayana/telegabber/xmpp/gateway" log "github.com/sirupsen/logrus" + "github.com/soheilhy/args" "gosrc.io/xmpp" "gosrc.io/xmpp/stanza" ) @@ -349,11 +350,18 @@ func handlePresence(s xmpp.Sender, p stanza.Presence) { log.Error(errors.Wrap(err, "TDlib connection failure")) } else { for status := range session.StatusesRange() { + show, description, typ := status.Destruct() + newArgs := []args.V{ + gateway.SPImmed(false), + } + if typ != "" { + newArgs = append(newArgs, gateway.SPType(typ)) + } go session.ProcessStatusUpdate( status.ID, - status.Description, - status.XMPP, - gateway.SPImmed(false), + description, + show, + newArgs..., ) } session.UpdateChatNicknames() From 64515e2c666067953e3a9680b4f0db84f3838498 Mon Sep 17 00:00:00 2001 From: Bohdan Horbeshko Date: Tue, 8 Aug 2023 00:54:24 -0400 Subject: [PATCH 4/4] Fix replies to messages with non-ASCII characters --- Makefile | 2 +- telegabber.go | 2 +- xmpp/handlers.go | 7 ++++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 33bedad..ef6aef4 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ COMMIT := $(shell git rev-parse --short HEAD) TD_COMMIT := "8517026415e75a8eec567774072cbbbbb52376c1" -VERSION := "v1.7.5" +VERSION := "v1.7.6" MAKEOPTS := "-j4" all: diff --git a/telegabber.go b/telegabber.go index 37d5890..3802764 100644 --- a/telegabber.go +++ b/telegabber.go @@ -15,7 +15,7 @@ import ( goxmpp "gosrc.io/xmpp" ) -var version string = "1.7.5" +var version string = "1.7.6" var commit string var sm *goxmpp.StreamManager diff --git a/xmpp/handlers.go b/xmpp/handlers.go index e85dfc9..36f9cf9 100644 --- a/xmpp/handlers.go +++ b/xmpp/handlers.go @@ -149,7 +149,12 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) { "end": body.End, }).Warn(errors.Wrap(err, "Failed to parse fallback end!")) } - text = text[:start] + text[end:] + + fullRunes := []rune(text) + cutRunes := make([]rune, 0, len(text)-int(end-start)) + cutRunes = append(cutRunes, fullRunes[:start]...) + cutRunes = append(cutRunes, fullRunes[end:]...) + text = string(cutRunes) } } var replaceId int64