Reflect Telegram edits natively by nativeedits option
This commit is contained in:
parent
c141c4ad2b
commit
ea004b7f7c
|
@ -43,6 +43,7 @@ type Session struct {
|
||||||
Carbons bool `yaml:":carbons"`
|
Carbons bool `yaml:":carbons"`
|
||||||
HideIds bool `yaml:":hideids"`
|
HideIds bool `yaml:":hideids"`
|
||||||
Receipts bool `yaml:":receipts"`
|
Receipts bool `yaml:":receipts"`
|
||||||
|
NativeEdits bool `yaml:":nativeedits"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var configKeys = []string{
|
var configKeys = []string{
|
||||||
|
@ -54,6 +55,7 @@ var configKeys = []string{
|
||||||
"carbons",
|
"carbons",
|
||||||
"hideids",
|
"hideids",
|
||||||
"receipts",
|
"receipts",
|
||||||
|
"nativeedits",
|
||||||
}
|
}
|
||||||
|
|
||||||
var sessionDB *SessionsYamlDB
|
var sessionDB *SessionsYamlDB
|
||||||
|
@ -134,6 +136,8 @@ func (s *Session) Get(key string) (string, error) {
|
||||||
return fromBool(s.HideIds), nil
|
return fromBool(s.HideIds), nil
|
||||||
case "receipts":
|
case "receipts":
|
||||||
return fromBool(s.Receipts), nil
|
return fromBool(s.Receipts), nil
|
||||||
|
case "nativeedits":
|
||||||
|
return fromBool(s.NativeEdits), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", errors.New("Unknown session property")
|
return "", errors.New("Unknown session property")
|
||||||
|
@ -205,6 +209,13 @@ func (s *Session) Set(key string, value string) (string, error) {
|
||||||
}
|
}
|
||||||
s.Receipts = b
|
s.Receipts = b
|
||||||
return value, nil
|
return value, nil
|
||||||
|
case "nativeedits":
|
||||||
|
b, err := toBool(value)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
s.NativeEdits = b
|
||||||
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", errors.New("Unknown session property")
|
return "", errors.New("Unknown session property")
|
||||||
|
|
|
@ -45,6 +45,7 @@ type Client struct {
|
||||||
DelayedStatusesLock sync.Mutex
|
DelayedStatusesLock sync.Mutex
|
||||||
|
|
||||||
lastMsgHashes map[int64]uint64
|
lastMsgHashes map[int64]uint64
|
||||||
|
lastMsgIds map[int64]string
|
||||||
msgHashSeed maphash.Seed
|
msgHashSeed maphash.Seed
|
||||||
|
|
||||||
locks clientLocks
|
locks clientLocks
|
||||||
|
@ -58,6 +59,7 @@ type clientLocks struct {
|
||||||
outboxLock sync.Mutex
|
outboxLock sync.Mutex
|
||||||
editOutboxLock sync.Mutex
|
editOutboxLock sync.Mutex
|
||||||
lastMsgHashesLock sync.Mutex
|
lastMsgHashesLock sync.Mutex
|
||||||
|
lastMsgIdsLock sync.RWMutex
|
||||||
|
|
||||||
authorizerReadLock sync.Mutex
|
authorizerReadLock sync.Mutex
|
||||||
authorizerWriteLock sync.Mutex
|
authorizerWriteLock sync.Mutex
|
||||||
|
@ -119,6 +121,7 @@ func NewClient(conf config.TelegramConfig, jid string, component *xmpp.Component
|
||||||
options: options,
|
options: options,
|
||||||
DelayedStatuses: make(map[int64]*DelayedStatus),
|
DelayedStatuses: make(map[int64]*DelayedStatus),
|
||||||
lastMsgHashes: make(map[int64]uint64),
|
lastMsgHashes: make(map[int64]uint64),
|
||||||
|
lastMsgIds: make(map[int64]string),
|
||||||
msgHashSeed: maphash.MakeSeed(),
|
msgHashSeed: maphash.MakeSeed(),
|
||||||
locks: clientLocks{
|
locks: clientLocks{
|
||||||
chatMessageLocks: make(map[int64]*sync.Mutex),
|
chatMessageLocks: make(map[int64]*sync.Mutex),
|
||||||
|
|
|
@ -201,6 +201,7 @@ func (c *Client) sendMessagesReverse(chatID int64, messages []*client.Message) {
|
||||||
strconv.FormatInt(message.Id, 10),
|
strconv.FormatInt(message.Id, 10),
|
||||||
c.xmpp,
|
c.xmpp,
|
||||||
reply,
|
reply,
|
||||||
|
"",
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
@ -380,9 +381,20 @@ func (c *Client) ProcessTransportCommand(cmdline string, resource string) string
|
||||||
}
|
}
|
||||||
case "config":
|
case "config":
|
||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
|
var msg string
|
||||||
if gateway.MessageOutgoingPermissionVersion == 0 && 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"
|
return "The server did not allow to enable carbons"
|
||||||
}
|
}
|
||||||
|
if !c.Session.RawMessages && args[0] == "nativeedits" && args[1] == "true" {
|
||||||
|
return "nativeedits only works with rawmessages as of yet, enable it first"
|
||||||
|
}
|
||||||
|
if c.Session.NativeEdits && args[0] == "rawmessages" && args[1] == "false" {
|
||||||
|
_, err := c.Session.Set("nativeedits", "false")
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
msg = "Automatically disabling nativeedits too...\n"
|
||||||
|
}
|
||||||
|
|
||||||
value, err := c.Session.Set(args[0], args[1])
|
value, err := c.Session.Set(args[0], args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -390,7 +402,7 @@ func (c *Client) ProcessTransportCommand(cmdline string, resource string) string
|
||||||
}
|
}
|
||||||
gateway.DirtySessions = true
|
gateway.DirtySessions = true
|
||||||
|
|
||||||
return fmt.Sprintf("%s set to %s", args[0], value)
|
return fmt.Sprintf("%s%s set to %s", msg, args[0], value)
|
||||||
} else if len(args) > 0 {
|
} else if len(args) > 0 {
|
||||||
value, err := c.Session.Get(args[0])
|
value, err := c.Session.Get(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -269,9 +269,9 @@ func (c *Client) updateMessageContent(update *client.UpdateMessageContent) {
|
||||||
|
|
||||||
c.SendMessageLock.Lock()
|
c.SendMessageLock.Lock()
|
||||||
c.SendMessageLock.Unlock()
|
c.SendMessageLock.Unlock()
|
||||||
xmppId, err := gateway.IdsDB.GetByTgIds(c.Session.Login, c.jid, update.ChatId, update.MessageId)
|
xmppId, xmppIdErr := gateway.IdsDB.GetByTgIds(c.Session.Login, c.jid, update.ChatId, update.MessageId)
|
||||||
var ignoredResource string
|
var ignoredResource string
|
||||||
if err == nil {
|
if xmppIdErr == nil {
|
||||||
ignoredResource = c.popFromEditOutbox(xmppId)
|
ignoredResource = c.popFromEditOutbox(xmppId)
|
||||||
} else {
|
} else {
|
||||||
log.Infof("Couldn't retrieve XMPP message ids for %v, an echo may happen", update.MessageId)
|
log.Infof("Couldn't retrieve XMPP message ids for %v, an echo may happen", update.MessageId)
|
||||||
|
@ -286,19 +286,50 @@ func (c *Client) updateMessageContent(update *client.UpdateMessageContent) {
|
||||||
|
|
||||||
if update.NewContent.MessageContentType() == client.TypeMessageText && c.hasLastMessageHashChanged(update.ChatId, update.MessageId, update.NewContent) {
|
if update.NewContent.MessageContentType() == client.TypeMessageText && c.hasLastMessageHashChanged(update.ChatId, update.MessageId, update.NewContent) {
|
||||||
textContent := update.NewContent.(*client.MessageText)
|
textContent := update.NewContent.(*client.MessageText)
|
||||||
|
var replaceId string
|
||||||
|
sId := strconv.FormatInt(update.MessageId, 10)
|
||||||
|
var isCarbon bool
|
||||||
|
|
||||||
|
// use XEP-0308 edits only if the last message is edited for sure, fallback otherwise
|
||||||
|
if c.Session.NativeEdits {
|
||||||
|
lastXmppId, ok := c.getLastChatMessageId(update.ChatId)
|
||||||
|
if xmppIdErr != nil {
|
||||||
|
xmppId = sId
|
||||||
|
}
|
||||||
|
if ok && lastXmppId == xmppId {
|
||||||
|
replaceId = xmppId
|
||||||
|
message, err := c.client.GetMessage(&client.GetMessageRequest{
|
||||||
|
ChatId: update.ChatId,
|
||||||
|
MessageId: update.MessageId,
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
isCarbon = c.isCarbonsEnabled() && message.IsOutgoing
|
||||||
|
} else {
|
||||||
|
log.Errorf("No message %v/%v found, cannot reliably determine if it's a carbon", update.ChatId, update.MessageId)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Infof("Mismatching message ids: %v %v, falling back to separate edit message", lastXmppId, xmppId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text := formatter.Format(
|
||||||
|
textContent.Text.Text,
|
||||||
|
textContent.Text.Entities,
|
||||||
|
markupFunction,
|
||||||
|
)
|
||||||
|
|
||||||
|
if replaceId == "" {
|
||||||
var editChar string
|
var editChar string
|
||||||
if c.Session.AsciiArrows {
|
if c.Session.AsciiArrows {
|
||||||
editChar = "e "
|
editChar = "e "
|
||||||
} else {
|
} else {
|
||||||
editChar = "✎ "
|
editChar = "✎ "
|
||||||
}
|
}
|
||||||
text := editChar + fmt.Sprintf("%v | %s", update.MessageId, formatter.Format(
|
text = editChar + fmt.Sprintf("%v | %s", update.MessageId, text)
|
||||||
textContent.Text.Text,
|
}
|
||||||
textContent.Text.Entities,
|
|
||||||
markupFunction,
|
|
||||||
))
|
|
||||||
for _, jid := range jids {
|
for _, jid := range jids {
|
||||||
gateway.SendMessage(jid, strconv.FormatInt(update.ChatId, 10), text, "e"+strconv.FormatInt(update.MessageId, 10), c.xmpp, nil, false, false)
|
gateway.SendMessage(jid, strconv.FormatInt(update.ChatId, 10), text, "e"+sId, c.xmpp, nil, replaceId, isCarbon, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -911,14 +911,17 @@ func (c *Client) countCharsInLines(lines *[]string) (count int) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) isCarbonsEnabled() bool {
|
||||||
|
return gateway.MessageOutgoingPermissionVersion > 0 && c.Session.Carbons
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) messageToPrefix(message *client.Message, previewString string, fileString string) (string, *gateway.Reply) {
|
func (c *Client) messageToPrefix(message *client.Message, previewString string, fileString string) (string, *gateway.Reply) {
|
||||||
isPM, err := c.IsPM(message.ChatId)
|
isPM, err := c.IsPM(message.ChatId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Could not determine if chat is PM: %v", err)
|
log.Errorf("Could not determine if chat is PM: %v", err)
|
||||||
}
|
}
|
||||||
isCarbonsEnabled := gateway.MessageOutgoingPermissionVersion > 0 && c.Session.Carbons
|
|
||||||
// with carbons, hide for all messages in PM and only for outgoing in group chats
|
// with carbons, hide for all messages in PM and only for outgoing in group chats
|
||||||
hideSender := isCarbonsEnabled && (message.IsOutgoing || isPM)
|
hideSender := c.isCarbonsEnabled() && (message.IsOutgoing || isPM)
|
||||||
|
|
||||||
prefix := []string{}
|
prefix := []string{}
|
||||||
// message direction
|
// message direction
|
||||||
|
@ -1007,7 +1010,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
|
// ProcessIncomingMessage transfers a message to XMPP side and marks it as read on Telegram side
|
||||||
func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) {
|
func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) {
|
||||||
isCarbon := gateway.MessageOutgoingPermissionVersion > 0 && c.Session.Carbons && message.IsOutgoing
|
isCarbon := c.isCarbonsEnabled() && message.IsOutgoing
|
||||||
jids := c.getCarbonFullJids(isCarbon, "")
|
jids := c.getCarbonFullJids(isCarbon, "")
|
||||||
|
|
||||||
var text, oob, auxText string
|
var text, oob, auxText string
|
||||||
|
@ -1083,11 +1086,12 @@ func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) {
|
||||||
sChatId := strconv.FormatInt(chatId, 10)
|
sChatId := strconv.FormatInt(chatId, 10)
|
||||||
|
|
||||||
for _, jid := range jids {
|
for _, jid := range jids {
|
||||||
gateway.SendMessageWithOOB(jid, sChatId, text, sId, c.xmpp, reply, oob, isCarbon, c.Session.Receipts)
|
gateway.SendMessageWithOOB(jid, sChatId, text, sId, c.xmpp, reply, oob, "", isCarbon, c.Session.Receipts)
|
||||||
if auxText != "" {
|
if auxText != "" {
|
||||||
gateway.SendMessage(jid, sChatId, auxText, sId, c.xmpp, reply, isCarbon, c.Session.Receipts)
|
gateway.SendMessage(jid, sChatId, auxText, sId, c.xmpp, reply, "", isCarbon, c.Session.Receipts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
c.UpdateLastChatMessageId(chatId, sId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarkAsRead marks a message as read
|
// MarkAsRead marks a message as read
|
||||||
|
@ -1588,6 +1592,21 @@ func (c *Client) hasLastMessageHashChanged(chatId, messageId int64, content clie
|
||||||
return !ok || oldHash != newHash
|
return !ok || oldHash != newHash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) UpdateLastChatMessageId(chatId int64, messageId string) {
|
||||||
|
c.locks.lastMsgIdsLock.Lock()
|
||||||
|
defer c.locks.lastMsgIdsLock.Unlock()
|
||||||
|
|
||||||
|
c.lastMsgIds[chatId] = messageId
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getLastChatMessageId(chatId int64) (string, bool) {
|
||||||
|
c.locks.lastMsgIdsLock.RLock()
|
||||||
|
defer c.locks.lastMsgIdsLock.RUnlock()
|
||||||
|
|
||||||
|
xmppId, ok := c.lastMsgIds[chatId]
|
||||||
|
return xmppId, ok
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) getFormatter() formatter.MarkupModeType {
|
func (c *Client) getFormatter() formatter.MarkupModeType {
|
||||||
return formatter.MarkupModeXEP0393
|
return formatter.MarkupModeXEP0393
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,23 +54,23 @@ var DirtySessions = false
|
||||||
var MessageOutgoingPermissionVersion = 0
|
var MessageOutgoingPermissionVersion = 0
|
||||||
|
|
||||||
// SendMessage creates and sends a message stanza
|
// SendMessage creates and sends a message stanza
|
||||||
func SendMessage(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, isCarbon, requestReceipt bool) {
|
func SendMessage(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, replaceId string, isCarbon, requestReceipt bool) {
|
||||||
sendMessageWrapper(to, from, body, id, component, reply, nil, "", isCarbon, requestReceipt)
|
sendMessageWrapper(to, from, body, id, component, reply, nil, "", replaceId, isCarbon, requestReceipt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendServiceMessage creates and sends a simple message stanza from transport
|
// SendServiceMessage creates and sends a simple message stanza from transport
|
||||||
func SendServiceMessage(to string, body string, component *xmpp.Component) {
|
func SendServiceMessage(to string, body string, component *xmpp.Component) {
|
||||||
sendMessageWrapper(to, "", body, "", component, nil, nil, "", false, false)
|
sendMessageWrapper(to, "", body, "", component, nil, nil, "", "", false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendTextMessage creates and sends a simple message stanza
|
// SendTextMessage creates and sends a simple message stanza
|
||||||
func SendTextMessage(to string, from string, body string, component *xmpp.Component) {
|
func SendTextMessage(to string, from string, body string, component *xmpp.Component) {
|
||||||
sendMessageWrapper(to, from, body, "", component, nil, nil, "", false, false)
|
sendMessageWrapper(to, from, body, "", component, nil, nil, "", "", false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendMessageWithOOB creates and sends a message stanza with OOB URL
|
// 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, requestReceipt bool) {
|
func SendMessageWithOOB(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, oob, replaceId string, isCarbon, requestReceipt bool) {
|
||||||
sendMessageWrapper(to, from, body, id, component, reply, nil, oob, isCarbon, requestReceipt)
|
sendMessageWrapper(to, from, body, id, component, reply, nil, oob, replaceId, isCarbon, requestReceipt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendMessageMarker creates and sends a message stanza with a XEP-0333 marker
|
// SendMessageMarker creates and sends a message stanza with a XEP-0333 marker
|
||||||
|
@ -78,10 +78,10 @@ func SendMessageMarker(to string, from string, component *xmpp.Component, marker
|
||||||
sendMessageWrapper(to, from, "", "", component, nil, &marker{
|
sendMessageWrapper(to, from, "", "", component, nil, &marker{
|
||||||
Type: markerType,
|
Type: markerType,
|
||||||
Id: markerId,
|
Id: markerId,
|
||||||
}, "", false, false)
|
}, "", "", false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendMessageWrapper(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, marker *marker, oob string, isCarbon, requestReceipt bool) {
|
func sendMessageWrapper(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, marker *marker, oob, replaceId string, isCarbon, requestReceipt bool) {
|
||||||
toJid, err := stanza.NewJid(to)
|
toJid, err := stanza.NewJid(to)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
|
@ -153,6 +153,9 @@ func sendMessageWrapper(to string, from string, body string, id string, componen
|
||||||
if requestReceipt {
|
if requestReceipt {
|
||||||
message.Extensions = append(message.Extensions, stanza.Markable{})
|
message.Extensions = append(message.Extensions, stanza.Markable{})
|
||||||
}
|
}
|
||||||
|
if replaceId != "" {
|
||||||
|
message.Extensions = append(message.Extensions, extensions.Replace{Id: replaceId})
|
||||||
|
}
|
||||||
|
|
||||||
if isCarbon {
|
if isCarbon {
|
||||||
carbonMessage := extensions.ClientMessage{
|
carbonMessage := extensions.ClientMessage{
|
||||||
|
|
|
@ -204,6 +204,7 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) {
|
||||||
err = gateway.IdsDB.Set(session.Session.Login, bare, toID, tgMessageId, msg.Id)
|
err = gateway.IdsDB.Set(session.Session.Login, bare, toID, tgMessageId, msg.Id)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
session.AddToOutbox(msg.Id, resource)
|
session.AddToOutbox(msg.Id, resource)
|
||||||
|
session.UpdateLastChatMessageId(toID, msg.Id)
|
||||||
} else {
|
} else {
|
||||||
log.Errorf("Failed to save ids %v/%v %v", toID, tgMessageId, msg.Id)
|
log.Errorf("Failed to save ids %v/%v %v", toID, tgMessageId, msg.Id)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue