Make members visitors if message sending is restricted for all in a chat

This commit is contained in:
Bohdan Horbeshko 2025-06-17 02:00:42 -04:00
parent 67c960da25
commit 06a6682bfa
4 changed files with 75 additions and 9 deletions

View file

@ -32,6 +32,7 @@ type MUCOccupant struct {
Nickname string Nickname string
Affiliation string Affiliation string
Role string Role string
Status client.ChatMemberStatus
} }
func NewMUCState() *MUCState { func NewMUCState() *MUCState {

View file

@ -133,6 +133,9 @@ func (c *Client) updateHandler() {
case client.TypeUpdateBasicGroupFullInfo: case client.TypeUpdateBasicGroupFullInfo:
typedUpdate, _ := update.(*client.UpdateBasicGroupFullInfo) typedUpdate, _ := update.(*client.UpdateBasicGroupFullInfo)
c.updateBasicGroupFullInfo(typedUpdate) c.updateBasicGroupFullInfo(typedUpdate)
case client.TypeUpdateChatPermissions:
typedUpdate, _ := update.(*client.UpdateChatPermissions)
c.updateChatPermissions(typedUpdate)
default: default:
// log only handled types // log only handled types
continue continue
@ -496,3 +499,38 @@ func (c *Client) updateBasicGroupFullInfo(update *client.UpdateBasicGroupFullInf
c.locks.mucCacheLock.Unlock() 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()
}
}

View file

@ -622,12 +622,15 @@ func (c *Client) updateMUCOccupants(mucState *MUCState, chatID int64, members []
myAffiliation := "member" myAffiliation := "member"
myRole := "participant" myRole := "participant"
chat, _, _ := c.GetContactByID(chatID, nil)
for _, member := range members { for _, member := range members {
senderId, nickname, affiliation, role := c.TgMemberToMUCOccupant(member) senderId, nickname, affiliation, role := c.TgMemberToMUCOccupant(member, chat)
mucState.Occupants[senderId] = &MUCOccupant{ mucState.Occupants[senderId] = &MUCOccupant{
Nickname: nickname, Nickname: nickname,
Affiliation: affiliation, Affiliation: affiliation,
Role: role, Role: role,
Status: member.Status,
} }
if c.me != nil && senderId == c.me.Id { if c.me != nil && senderId == c.me.Id {
@ -670,7 +673,7 @@ func (c *Client) mucCacheHasOccupant(mucID int64, memberID int64) bool {
return ok 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() c.locks.mucCacheLock.Lock()
defer c.locks.mucCacheLock.Unlock() defer c.locks.mucCacheLock.Unlock()
mucState, ok := c.mucCache[mucID] mucState, ok := c.mucCache[mucID]
@ -694,6 +697,7 @@ func (c *Client) addMUCOccupant(mucID int64, memberID int64, affiliation, role s
Nickname: nickname, Nickname: nickname,
Affiliation: affiliation, Affiliation: affiliation,
Role: role, Role: role,
Status: status,
} }
return true return true
} }
@ -745,6 +749,7 @@ func (c *Client) updateMUCsNickname(memberID int64, newNickname string) {
Nickname: newNickname, Nickname: newNickname,
Affiliation: oldOccupant.Affiliation, Affiliation: oldOccupant.Affiliation,
Role: oldOccupant.Role, Role: oldOccupant.Role,
Status: oldOccupant.Status,
} }
sMucId := gateway.MUCNODE(mucId) sMucId := gateway.MUCNODE(mucId)
@ -1659,8 +1664,8 @@ func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) {
if err == nil { if err == nil {
status = chatMember.Status status = chatMember.Status
} }
affiliation, role := c.memberStatusToAffiliationAndRole(status) affiliation, role := c.memberStatusToAffiliationAndRole(status, chat)
safeToSend = c.addMUCOccupant(chatId, senderId, affiliation, role) safeToSend = c.addMUCOccupant(chatId, senderId, affiliation, role, status)
} }
groupChatFrom = gateway.MUCJID(chatId) + "/" + c.GetMUCNickname(senderId) groupChatFrom = gateway.MUCJID(chatId) + "/" + c.GetMUCNickname(senderId)
@ -2462,7 +2467,7 @@ func (c *Client) usernamesToString(usernames []string) string {
return strings.Join(atUsernames, ", ") 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 { if memberStatus != nil {
switch memberStatus.ChatMemberStatusType() { switch memberStatus.ChatMemberStatusType() {
case client.TypeChatMemberStatusCreator: case client.TypeChatMemberStatusCreator:
@ -2470,10 +2475,13 @@ func (c *Client) memberStatusToAffiliationAndRole(memberStatus client.ChatMember
case client.TypeChatMemberStatusAdministrator: case client.TypeChatMemberStatusAdministrator:
return "admin", "moderator" return "admin", "moderator"
case client.TypeChatMemberStatusMember: case client.TypeChatMemberStatusMember:
if chat != nil && !c.IsMessageSendingPermitted(chat.Permissions) {
return "member", "visitor"
}
return "member", "participant" return "member", "participant"
case client.TypeChatMemberStatusRestricted: case client.TypeChatMemberStatusRestricted:
restricted, _ := memberStatus.(*client.ChatMemberStatusRestricted) restricted, _ := memberStatus.(*client.ChatMemberStatusRestricted)
if restricted.Permissions != nil && !restricted.Permissions.CanSendBasicMessages { if !c.IsMessageSendingPermitted(restricted.Permissions) {
return "member", "visitor" return "member", "visitor"
} }
return "member", "participant" return "member", "participant"
@ -2487,10 +2495,10 @@ func (c *Client) memberStatusToAffiliationAndRole(memberStatus client.ChatMember
} }
// TgMemberToMUCMember resolves useful data to generate a MUC occupant // 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) senderId = c.GetSenderId(member.MemberId)
nickname = c.GetMUCNickname(senderId) nickname = c.GetMUCNickname(senderId)
affiliation, role = c.memberStatusToAffiliationAndRole(member.Status) affiliation, role = c.memberStatusToAffiliationAndRole(member.Status, chat)
return return
} }
@ -2736,6 +2744,23 @@ func (c *Client) mucOccupantRolePresence(chatID, userID int64, status ChatMember
c.locks.mucCacheLock.Unlock() 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 // GetErrorCode obtains an error code from a Telegram response error
func GetErrorCode(err error) (int32, bool) { func GetErrorCode(err error) (int32, bool) {
responseError, ok := err.(client.ResponseError) responseError, ok := err.(client.ResponseError)

View file

@ -1212,8 +1212,10 @@ func handleGetQueryMucAdmin(s xmpp.Sender, iq *stanza.IQ, query *extensions.Quer
members, err := session.GetChatMembers(toID, false, "", membersList) members, err := session.GetChatMembers(toID, false, "", membersList)
if err == nil { if err == nil {
chat, _, _ := session.GetContactByID(toID, nil)
for _, member := range members { 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 { if item.Role != "" && role != item.Role {
continue continue
} }