diff --git a/telegram/client.go b/telegram/client.go index 56cd323..f10bf44 100644 --- a/telegram/client.go +++ b/telegram/client.go @@ -69,6 +69,7 @@ type Client struct { outbox map[string]string editOutbox map[string]string + pinOutbox map[int64]chan int64 DelayedStatuses map[int64]*DelayedStatus DelayedStatusesLock sync.Mutex @@ -98,6 +99,7 @@ type clientLocks struct { outboxLock sync.Mutex mucCacheLock sync.Mutex editOutboxLock sync.Mutex + pinOutboxLock sync.Mutex lastMsgHashesLock sync.Mutex lastMsgIdsLock sync.RWMutex @@ -167,6 +169,7 @@ func NewClient(conf config.TelegramConfig, jid string, component *xmpp.Component cache: cache.NewCache(), outbox: make(map[string]string), editOutbox: make(map[string]string), + pinOutbox: make(map[int64]chan int64), mucCache: make(map[int64]*MUCState), options: options, DelayedStatuses: make(map[int64]*DelayedStatus), diff --git a/telegram/handlers.go b/telegram/handlers.go index 11c38ba..a1fc001 100644 --- a/telegram/handlers.go +++ b/telegram/handlers.go @@ -452,6 +452,13 @@ func (c *Client) updateAuthorizationState(update *client.UpdateAuthorizationStat } func (c *Client) updateMessageSendSucceeded(update *client.UpdateMessageSendSucceeded) { + c.locks.pinOutboxLock.Lock() + ch, chOk := c.pinOutbox[update.OldMessageId] + if chOk { + ch <-update.Message.Id + } + c.locks.pinOutboxLock.Unlock() + // replace message ID in local database log.Debugf("replace message %v with %v", update.OldMessageId, update.Message.Id) if err := gateway.IdsDB.ReplaceTgId(c.Session.Login, c.jid, update.Message.ChatId, update.OldMessageId, update.Message.Id); err != nil { @@ -469,6 +476,13 @@ func (c *Client) updateMessageSendSucceeded(update *client.UpdateMessageSendSucc } } func (c *Client) updateMessageSendFailed(update *client.UpdateMessageSendFailed) { + c.locks.pinOutboxLock.Lock() + ch, chOk := c.pinOutbox[update.OldMessageId] + if chOk { + ch <-0 + } + c.locks.pinOutboxLock.Unlock() + // clean uploaded files file, _ := c.contentToFile(update.Message.Content) if file != nil && file.Local != nil { diff --git a/telegram/utils.go b/telegram/utils.go index d10810d..1c78320 100644 --- a/telegram/utils.go +++ b/telegram/utils.go @@ -808,6 +808,44 @@ func (c *Client) GetMyMUCNickname(chatID int64) (string, bool) { return member.Nickname, true } +// NewPinnedMessage sends a text message and pins it right away +func (c *Client) NewPinnedMessage(chatID int64, text, returnJid string) bool { + c.locks.pinOutboxLock.Lock() + msg := c.ProcessOutgoingMessage(chatID, text, returnJid, 0, 0, true, true) + if msg == nil { + c.locks.pinOutboxLock.Unlock() + return false + } + ch := make(chan int64) + c.pinOutbox[msg.Id] = ch + c.locks.pinOutboxLock.Unlock() + + newId := <-ch + + c.locks.pinOutboxLock.Lock() + delete(c.pinOutbox, msg.Id) + c.locks.pinOutboxLock.Unlock() + + if newId == 0 { + return false + } + + ok, err := c.client.PinChatMessage(&client.PinChatMessageRequest{ + ChatId: chatID, + MessageId: newId, + }) + if err != nil { + log.Errorf("failed to pin message: %v", err.Error()) + c.client.DeleteMessages(&client.DeleteMessagesRequest{ + ChatId: chatID, + MessageIds: []int64{msg.Id}, + Revoke: true, + }) + } + + return ok != nil +} + // FormatContact retrieves a complete "full name (@usernames)" string for display func (c *Client) FormatContact(chatID int64) string { if chatID == 0 { diff --git a/xmpp/handlers.go b/xmpp/handlers.go index a914214..a1dee50 100644 --- a/xmpp/handlers.go +++ b/xmpp/handlers.go @@ -342,6 +342,34 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) { } return } + + if msg.Thread == "" && msg.Subject != "" && msg.Type == "groupchat" { + log.Debugf("MUC subject change: %#v", msg) + + bare, _, ok := gateway.SplitJID(msg.From) + if !ok { + return + } + session, ok := sessions[bare] + if !ok { + return + } + toID, ok, isGroup := toToID(msg.To) + if !ok || !isGroup { + return + } + _, resource, ok := gateway.SplitJID(msg.To) + if ok && resource != "" { + return + } + + go func() { + pinOk := session.NewPinnedMessage(toID, msg.Subject, msg.From) + if !pinOk { + gateway.SendErrorMessage(msg.From, gateway.MUCJID(toID), "", 406, true, component) + } + }() + } } if msg.Type == "error" {