From ef831fc9725601a94149ce94c3fb686afc77e0a5 Mon Sep 17 00:00:00 2001 From: Bohdan Horbeshko Date: Mon, 31 Jul 2023 21:25:24 -0400 Subject: [PATCH] Migrate to TDLib 1.8.14 (multiple usernames support) --- go.mod | 1 + go.sum | 2 ++ telegram/client.go | 4 +-- telegram/commands.go | 26 +++++++++----- telegram/connect.go | 12 ++----- telegram/handlers.go | 2 +- telegram/utils.go | 80 ++++++++++++++++++++++++++++++++---------- telegram/utils_test.go | 47 +++++++++++++++++++++++++ xmpp/handlers.go | 8 ++--- 9 files changed, 138 insertions(+), 44 deletions(-) diff --git a/go.mod b/go.mod index a4e26d2..db7c380 100644 --- a/go.mod +++ b/go.mod @@ -34,3 +34,4 @@ require ( ) replace gosrc.io/xmpp => dev.narayana.im/narayana/go-xmpp v0.0.0-20220524203317-306b4ff58e8f +replace github.com/zelenin/go-tdlib => dev.narayana.im/narayana/go-tdlib v0.0.0-20230730021136-47da33180615 diff --git a/go.sum b/go.sum index 011bc93..2565582 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +dev.narayana.im/narayana/go-tdlib v0.0.0-20230730021136-47da33180615 h1:RRUZJSro+k8FkazNx7QEYLVoO4wZtchvsd0Y2RBWjeU= +dev.narayana.im/narayana/go-tdlib v0.0.0-20230730021136-47da33180615/go.mod h1:Xs8fXbk5n7VaPyrSs9DP7QYoBScWYsjX+lUcWmx1DIU= dev.narayana.im/narayana/go-xmpp v0.0.0-20220524203317-306b4ff58e8f h1:6249ajbMjgYz53Oq0IjTvjHXbxTfu29Mj1J/6swRHs4= dev.narayana.im/narayana/go-xmpp v0.0.0-20220524203317-306b4ff58e8f/go.mod h1:L3NFMqYOxyLz3JGmgFyWf7r9htE91zVGiK40oW4RwdY= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= diff --git a/telegram/client.go b/telegram/client.go index 5b0217a..e9acd20 100644 --- a/telegram/client.go +++ b/telegram/client.go @@ -45,7 +45,7 @@ type DelayedStatus struct { type Client struct { client *client.Client authorizer *clientAuthorizer - parameters *client.TdlibParameters + parameters *client.SetTdlibParametersRequest options []client.Option me *client.User @@ -100,7 +100,7 @@ func NewClient(conf config.TelegramConfig, jid string, component *xmpp.Component datadir = "./sessions/" // ye olde defaute } - parameters := client.TdlibParameters{ + parameters := client.SetTdlibParametersRequest{ UseTestDc: false, DatabaseDirectory: filepath.Join(datadir, jid), diff --git a/telegram/commands.go b/telegram/commands.go index 53b5d75..3828ec2 100644 --- a/telegram/commands.go +++ b/telegram/commands.go @@ -18,8 +18,7 @@ const notEnoughArguments string = "Not enough arguments" const telegramNotInitialized string = "Telegram connection is not initialized yet" const notOnline string = "Not online" -var permissionsAdmin = client.ChatMemberStatusAdministrator{ - CanBeEdited: true, +var permissionsAdmin = client.ChatAdministratorRights{ CanChangeInfo: true, CanPostMessages: true, CanEditMessages: true, @@ -30,14 +29,20 @@ var permissionsAdmin = client.ChatMemberStatusAdministrator{ CanPromoteMembers: false, } var permissionsMember = client.ChatPermissions{ - CanSendMessages: true, - CanSendMediaMessages: true, + CanSendBasicMessages: true, + CanSendAudios: true, + CanSendDocuments: true, + CanSendPhotos: true, + CanSendVideos: true, + CanSendVideoNotes: true, + CanSendVoiceNotes: true, CanSendPolls: true, CanSendOtherMessages: true, CanAddWebPagePreviews: true, CanChangeInfo: true, CanInviteUsers: true, CanPinMessages: true, + CanManageTopics: true, } var permissionsReadonly = client.ChatPermissions{} @@ -666,7 +671,7 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool) entries := []string{ keyValueString("Chat title", info.Fn), keyValueString("Photo", link), - keyValueString("Username", info.Nickname), + keyValueString("Usernames", c.usernamesToString(info.Nicknames)), keyValueString("Full name", info.Given+" "+info.Family), keyValueString("Phone number", info.Tel), } @@ -883,7 +888,10 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool) } // clone the permissions - status := permissionsAdmin + status := client.ChatMemberStatusAdministrator{ + CanBeEdited: true, + Rights: &permissionsAdmin, + } if len(args) > 1 { status.CustomTitle = args[1] @@ -933,9 +941,9 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool) return "Invalid TTL", true } } - _, err = c.client.SetChatMessageTtl(&client.SetChatMessageTtlRequest{ - ChatId: chatID, - Ttl: int32(ttl), + _, err = c.client.SetChatMessageAutoDeleteTime(&client.SetChatMessageAutoDeleteTimeRequest{ + ChatId: chatID, + MessageAutoDeleteTime: int32(ttl), }) if err != nil { diff --git a/telegram/connect.go b/telegram/connect.go index 8324319..ef03428 100644 --- a/telegram/connect.go +++ b/telegram/connect.go @@ -13,7 +13,7 @@ import ( const chatsLimit int32 = 999 type clientAuthorizer struct { - TdlibParameters chan *client.TdlibParameters + TdlibParameters chan *client.SetTdlibParametersRequest PhoneNumber chan string Code chan string State chan client.AuthorizationState @@ -31,13 +31,7 @@ func (stateHandler *clientAuthorizer) Handle(c *client.Client, state client.Auth switch state.AuthorizationStateType() { case client.TypeAuthorizationStateWaitTdlibParameters: - _, err := c.SetTdlibParameters(&client.SetTdlibParametersRequest{ - Parameters: <-stateHandler.TdlibParameters, - }) - return err - - case client.TypeAuthorizationStateWaitEncryptionKey: - _, err := c.CheckDatabaseEncryptionKey(&client.CheckDatabaseEncryptionKeyRequest{}) + _, err := c.SetTdlibParameters(<-stateHandler.TdlibParameters) return err case client.TypeAuthorizationStateWaitPhoneNumber: @@ -116,7 +110,7 @@ func (c *Client) Connect(resource string) error { log.Warn("Connecting to Telegram network...") c.authorizer = &clientAuthorizer{ - TdlibParameters: make(chan *client.TdlibParameters, 1), + TdlibParameters: make(chan *client.SetTdlibParametersRequest, 1), PhoneNumber: make(chan string, 1), Code: make(chan string, 1), State: make(chan client.AuthorizationState, 10), diff --git a/telegram/handlers.go b/telegram/handlers.go index cc6e635..cedea63 100644 --- a/telegram/handlers.go +++ b/telegram/handlers.go @@ -233,7 +233,7 @@ func (c *Client) updateNewMessage(update *client.UpdateNewMessage) { // message content updated func (c *Client) updateMessageContent(update *client.UpdateMessageContent) { - markupFunction := formatter.EntityToXEP0393 + markupFunction := c.getFormatter() defer c.updateLastMessageHash(update.ChatId, update.MessageId, update.NewContent) diff --git a/telegram/utils.go b/telegram/utils.go index 4835696..e1e9317 100644 --- a/telegram/utils.go +++ b/telegram/utils.go @@ -27,13 +27,13 @@ import ( ) type VCardInfo struct { - Fn string - Photo *client.File - Nickname string - Given string - Family string - Tel string - Info string + Fn string + Photo *client.File + Nicknames []string + Given string + Family string + Tel string + Info string } var errOffline = errors.New("TDlib instance is offline") @@ -286,12 +286,15 @@ func (c *Client) formatContact(chatID int64) string { if chat != nil { str = fmt.Sprintf("%s (%v)", chat.Title, chat.Id) } else if user != nil { - username := user.Username - if username == "" { - username = strconv.FormatInt(user.Id, 10) + var usernames string + if user.Usernames != nil { + usernames = c.usernamesToString(user.Usernames.ActiveUsernames) + } + if usernames == "" { + usernames = strconv.FormatInt(user.Id, 10) } - str = fmt.Sprintf("%s %s (%v)", user.FirstName, user.LastName, username) + str = fmt.Sprintf("%s %s (%v)", user.FirstName, user.LastName, usernames) } else { str = strconv.FormatInt(chatID, 10) } @@ -566,7 +569,7 @@ func (c *Client) messageToText(message *client.Message, preview bool) string { return "" } - markupFunction := formatter.EntityToXEP0393 + markupFunction := c.getFormatter() switch message.Content.MessageContentType() { case client.TypeMessageSticker: sticker, _ := message.Content.(*client.MessageSticker) @@ -737,6 +740,22 @@ func (c *Client) messageToText(message *client.Message, preview bool) string { return strings.Join(rows, "\n") } + case client.TypeMessageChatSetMessageAutoDeleteTime: + ttl, _ := message.Content.(*client.MessageChatSetMessageAutoDeleteTime) + name := c.formatContact(ttl.FromUserId) + if name == "" { + if ttl.MessageAutoDeleteTime == 0 { + return "The self-destruct timer was disabled" + } else { + return fmt.Sprintf("The self-destruct timer was set to %v seconds", ttl.MessageAutoDeleteTime) + } + } else { + if ttl.MessageAutoDeleteTime == 0 { + return fmt.Sprintf("%s disabled the self-destruct timer", name) + } else { + return fmt.Sprintf("%s set the self-destruct timer to %v seconds", name, ttl.MessageAutoDeleteTime) + } + } } return fmt.Sprintf("unknown message (%s)", message.Content.MessageContentType()) @@ -751,7 +770,7 @@ func (c *Client) contentToFile(content client.MessageContent) (*client.File, *cl case client.TypeMessageSticker: sticker, _ := content.(*client.MessageSticker) file := sticker.Sticker.Sticker - if sticker.Sticker.IsAnimated && sticker.Sticker.Thumbnail != nil && sticker.Sticker.Thumbnail.File != nil { + if sticker.Sticker.Format.StickerFormatType() != client.TypeStickerTypeRegular && sticker.Sticker.Thumbnail != nil && sticker.Sticker.Thumbnail.File != nil { file = sticker.Sticker.Thumbnail.File } return file, nil @@ -1192,7 +1211,7 @@ func (c *Client) roster(resource string) { } // get last messages from specified chat -func (c *Client) getLastMessages(id int64, query string, from int64, count int32) (*client.Messages, error) { +func (c *Client) getLastMessages(id int64, query string, from int64, count int32) (*client.FoundChatMessages, error) { return c.client.SearchChatMessages(&client.SearchChatMessagesRequest{ ChatId: id, Query: query, @@ -1245,10 +1264,18 @@ func (c *Client) GetChatDescription(chat *client.Chat) string { UserId: privateType.UserId, }) if err == nil { - if fullInfo.Bio != "" { - return fullInfo.Bio - } else if fullInfo.Description != "" { - return fullInfo.Description + if fullInfo.Bio != nil && fullInfo.Bio.Text != "" { + return formatter.Format( + fullInfo.Bio.Text, + fullInfo.Bio.Entities, + c.getFormatter(), + ) + } else if fullInfo.BotInfo != nil { + if fullInfo.BotInfo.ShortDescription != "" { + return fullInfo.BotInfo.ShortDescription + } else { + return fullInfo.BotInfo.Description + } } } else { log.Warnf("Coudln't retrieve private chat info: %v", err.Error()) @@ -1328,7 +1355,10 @@ func (c *Client) GetVcardInfo(toID int64) (VCardInfo, error) { info.Info = c.GetChatDescription(chat) } if user != nil { - info.Nickname = user.Username + if user.Usernames != nil { + info.Nicknames = make([]string, len(user.Usernames.ActiveUsernames)) + copy(info.Nicknames, user.Usernames.ActiveUsernames) + } info.Given = user.FirstName info.Family = user.LastName info.Tel = user.PhoneNumber @@ -1441,3 +1471,15 @@ func (c *Client) hasLastMessageHashChanged(chatId, messageId int64, content clie return !ok || oldHash != newHash } + +func (c *Client) getFormatter() func(*client.TextEntity) (*formatter.Insertion, *formatter.Insertion) { + return formatter.EntityToXEP0393 +} + +func (c *Client) usernamesToString(usernames []string) string { + var atUsernames []string + for _, username := range usernames { + atUsernames = append(atUsernames, "@"+username) + } + return strings.Join(atUsernames, ", ") +} diff --git a/telegram/utils_test.go b/telegram/utils_test.go index 91002ee..18be215 100644 --- a/telegram/utils_test.go +++ b/telegram/utils_test.go @@ -369,6 +369,53 @@ func TestMessageAnimation(t *testing.T) { } } +func TestMessageTtl1(t *testing.T) { + ttl := client.Message{ + Content: &client.MessageChatSetMessageAutoDeleteTime{}, + } + text := (&Client{}).messageToText(&ttl, false) + if text != "The self-destruct timer was disabled" { + t.Errorf("Wrong anonymous off ttl label: %v", text) + } +} + +func TestMessageTtl2(t *testing.T) { + ttl := client.Message{ + Content: &client.MessageChatSetMessageAutoDeleteTime{ + MessageAutoDeleteTime: 3, + }, + } + text := (&Client{}).messageToText(&ttl, false) + if text != "The self-destruct timer was set to 3 seconds" { + t.Errorf("Wrong anonymous ttl label: %v", text) + } +} + +func TestMessageTtl3(t *testing.T) { + ttl := client.Message{ + Content: &client.MessageChatSetMessageAutoDeleteTime{ + FromUserId: 3, + }, + } + text := (&Client{}).messageToText(&ttl, false) + if text != "unknown contact: TDlib instance is offline disabled the self-destruct timer" { + t.Errorf("Wrong off ttl label: %v", text) + } +} + +func TestMessageTtl4(t *testing.T) { + ttl := client.Message{ + Content: &client.MessageChatSetMessageAutoDeleteTime{ + FromUserId: 3, + MessageAutoDeleteTime: 3, + }, + } + text := (&Client{}).messageToText(&ttl, false) + if text != "unknown contact: TDlib instance is offline set the self-destruct timer to 3 seconds" { + t.Errorf("Wrong ttl label: %v", text) + } +} + func TestMessageUnknown(t *testing.T) { unknown := client.Message{ Content: &client.MessageExpiredPhoto{}, diff --git a/xmpp/handlers.go b/xmpp/handlers.go index c5ec029..fd1afad 100644 --- a/xmpp/handlers.go +++ b/xmpp/handlers.go @@ -481,7 +481,7 @@ func makeVCardPayload(typ byte, id string, info telegram.VCardInfo, session *tel vcard.Photo.Type.Text = "image/jpeg" vcard.Photo.Binval.Text = base64Photo } - vcard.Nickname.Text = info.Nickname + vcard.Nickname.Text = strings.Join(info.Nicknames, ",") vcard.N.Given.Text = info.Given vcard.N.Family.Text = info.Family vcard.Tel.Number.Text = info.Tel @@ -512,13 +512,13 @@ func makeVCardPayload(typ byte, id string, info telegram.VCardInfo, session *tel }, }) } - if info.Nickname != "" { + for _, nickname := range info.Nicknames { nodes = append(nodes, stanza.Node{ XMLName: xml.Name{Local: "nickname"}, Nodes: []stanza.Node{ stanza.Node{ XMLName: xml.Name{Local: "text"}, - Content: info.Nickname, + Content: nickname, }, }, }, stanza.Node{ @@ -526,7 +526,7 @@ func makeVCardPayload(typ byte, id string, info telegram.VCardInfo, session *tel Nodes: []stanza.Node{ stanza.Node{ XMLName: xml.Name{Local: "uri"}, - Content: "https://t.me/" + info.Nickname, + Content: "https://t.me/" + nickname, }, }, })