From 06a6682bfa4b674f40812b80ab85c24a293af653 Mon Sep 17 00:00:00 2001 From: Bohdan Horbeshko Date: Tue, 17 Jun 2025 02:00:42 -0400 Subject: [PATCH] Make members visitors if message sending is restricted for all in a chat --- telegram/client.go | 1 + telegram/handlers.go | 38 ++++++++++++++++++++++++++++++++++++++ telegram/utils.go | 41 +++++++++++++++++++++++++++++++++-------- xmpp/handlers.go | 4 +++- 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/telegram/client.go b/telegram/client.go index 29a8a00..22ad2b9 100644 --- a/telegram/client.go +++ b/telegram/client.go @@ -32,6 +32,7 @@ type MUCOccupant struct { Nickname string Affiliation string Role string + Status client.ChatMemberStatus } func NewMUCState() *MUCState { diff --git a/telegram/handlers.go b/telegram/handlers.go index 26f4bcf..e3a2e0a 100644 --- a/telegram/handlers.go +++ b/telegram/handlers.go @@ -133,6 +133,9 @@ func (c *Client) updateHandler() { case client.TypeUpdateBasicGroupFullInfo: typedUpdate, _ := update.(*client.UpdateBasicGroupFullInfo) c.updateBasicGroupFullInfo(typedUpdate) + case client.TypeUpdateChatPermissions: + typedUpdate, _ := update.(*client.UpdateChatPermissions) + c.updateChatPermissions(typedUpdate) default: // log only handled types continue @@ -496,3 +499,38 @@ func (c *Client) updateBasicGroupFullInfo(update *client.UpdateBasicGroupFullInf c.locks.mucCacheLock.Unlock() } } + +func (c *Client) updateChatPermissions(update *client.UpdateChatPermissions) { + chat, _, _ := c.GetContactByID(update.ChatId, nil) + + // update chat permissions in the cache + if chat != nil { + chat.Permissions = update.Permissions + } + + if c.Session.MUC { + c.locks.mucCacheLock.Lock() + + mucState, ok := c.mucCache[update.ChatId] + if ok && mucState != nil { + for memberID, occupant := range mucState.Occupants { + affiliation, role := c.memberStatusToAffiliationAndRole(occupant.Status, chat) + if affiliation != occupant.Affiliation || role != occupant.Role { + occupant.Affiliation = affiliation + occupant.Role = role + + c.sendPresence( + gateway.SPFrom(gateway.MUCNODE(update.ChatId)), + gateway.SPResource(occupant.Nickname), + gateway.SPImmed(true), + gateway.SPMUCJid(gateway.CHATJID(memberID, true)), + gateway.SPMUCAffiliation(affiliation), + gateway.SPMUCRole(role), + ) + } + } + } + + c.locks.mucCacheLock.Unlock() + } +} diff --git a/telegram/utils.go b/telegram/utils.go index f226303..352dc07 100644 --- a/telegram/utils.go +++ b/telegram/utils.go @@ -622,12 +622,15 @@ func (c *Client) updateMUCOccupants(mucState *MUCState, chatID int64, members [] myAffiliation := "member" myRole := "participant" + chat, _, _ := c.GetContactByID(chatID, nil) + for _, member := range members { - senderId, nickname, affiliation, role := c.TgMemberToMUCOccupant(member) + senderId, nickname, affiliation, role := c.TgMemberToMUCOccupant(member, chat) mucState.Occupants[senderId] = &MUCOccupant{ Nickname: nickname, Affiliation: affiliation, Role: role, + Status: member.Status, } if c.me != nil && senderId == c.me.Id { @@ -670,7 +673,7 @@ func (c *Client) mucCacheHasOccupant(mucID int64, memberID int64) bool { return ok } -func (c *Client) addMUCOccupant(mucID int64, memberID int64, affiliation, role string) bool { +func (c *Client) addMUCOccupant(mucID int64, memberID int64, affiliation, role string, status client.ChatMemberStatus) bool { c.locks.mucCacheLock.Lock() defer c.locks.mucCacheLock.Unlock() mucState, ok := c.mucCache[mucID] @@ -694,6 +697,7 @@ func (c *Client) addMUCOccupant(mucID int64, memberID int64, affiliation, role s Nickname: nickname, Affiliation: affiliation, Role: role, + Status: status, } return true } @@ -745,6 +749,7 @@ func (c *Client) updateMUCsNickname(memberID int64, newNickname string) { Nickname: newNickname, Affiliation: oldOccupant.Affiliation, Role: oldOccupant.Role, + Status: oldOccupant.Status, } sMucId := gateway.MUCNODE(mucId) @@ -1659,8 +1664,8 @@ func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) { if err == nil { status = chatMember.Status } - affiliation, role := c.memberStatusToAffiliationAndRole(status) - safeToSend = c.addMUCOccupant(chatId, senderId, affiliation, role) + affiliation, role := c.memberStatusToAffiliationAndRole(status, chat) + safeToSend = c.addMUCOccupant(chatId, senderId, affiliation, role, status) } groupChatFrom = gateway.MUCJID(chatId) + "/" + c.GetMUCNickname(senderId) @@ -2462,7 +2467,7 @@ func (c *Client) usernamesToString(usernames []string) string { return strings.Join(atUsernames, ", ") } -func (c *Client) memberStatusToAffiliationAndRole(memberStatus client.ChatMemberStatus) (string, string) { +func (c *Client) memberStatusToAffiliationAndRole(memberStatus client.ChatMemberStatus, chat *client.Chat) (string, string) { if memberStatus != nil { switch memberStatus.ChatMemberStatusType() { case client.TypeChatMemberStatusCreator: @@ -2470,10 +2475,13 @@ func (c *Client) memberStatusToAffiliationAndRole(memberStatus client.ChatMember case client.TypeChatMemberStatusAdministrator: return "admin", "moderator" case client.TypeChatMemberStatusMember: + if chat != nil && !c.IsMessageSendingPermitted(chat.Permissions) { + return "member", "visitor" + } return "member", "participant" case client.TypeChatMemberStatusRestricted: restricted, _ := memberStatus.(*client.ChatMemberStatusRestricted) - if restricted.Permissions != nil && !restricted.Permissions.CanSendBasicMessages { + if !c.IsMessageSendingPermitted(restricted.Permissions) { return "member", "visitor" } return "member", "participant" @@ -2487,10 +2495,10 @@ func (c *Client) memberStatusToAffiliationAndRole(memberStatus client.ChatMember } // TgMemberToMUCMember resolves useful data to generate a MUC occupant -func (c *Client) TgMemberToMUCOccupant(member *client.ChatMember) (senderId int64, nickname, affiliation, role string) { +func (c *Client) TgMemberToMUCOccupant(member *client.ChatMember, chat *client.Chat) (senderId int64, nickname, affiliation, role string) { senderId = c.GetSenderId(member.MemberId) nickname = c.GetMUCNickname(senderId) - affiliation, role = c.memberStatusToAffiliationAndRole(member.Status) + affiliation, role = c.memberStatusToAffiliationAndRole(member.Status, chat) return } @@ -2736,6 +2744,23 @@ func (c *Client) mucOccupantRolePresence(chatID, userID int64, status ChatMember c.locks.mucCacheLock.Unlock() } +// IsMessageSendingPermitted evaluates if permissions of the chat allow message sending +func (c *Client) IsMessageSendingPermitted(permissions *client.ChatPermissions) bool { + if permissions == nil { + return true + } + + return permissions.CanSendBasicMessages || + permissions.CanSendAudios || + permissions.CanSendDocuments || + permissions.CanSendPhotos || + permissions.CanSendVideos || + permissions.CanSendVideoNotes || + permissions.CanSendVoiceNotes || + permissions.CanSendPolls || + permissions.CanSendOtherMessages +} + // GetErrorCode obtains an error code from a Telegram response error func GetErrorCode(err error) (int32, bool) { responseError, ok := err.(client.ResponseError) diff --git a/xmpp/handlers.go b/xmpp/handlers.go index c663cc4..450ad9d 100644 --- a/xmpp/handlers.go +++ b/xmpp/handlers.go @@ -1212,8 +1212,10 @@ func handleGetQueryMucAdmin(s xmpp.Sender, iq *stanza.IQ, query *extensions.Quer members, err := session.GetChatMembers(toID, false, "", membersList) if err == nil { + chat, _, _ := session.GetContactByID(toID, nil) + for _, member := range members { - senderId, nickname, affiliation, role := session.TgMemberToMUCOccupant(member) + senderId, nickname, affiliation, role := session.TgMemberToMUCOccupant(member, chat) if item.Role != "" && role != item.Role { continue }