Display incoming messages from Telegram in MUCs

This commit is contained in:
Bohdan Horbeshko 2025-05-13 23:52:55 -04:00
parent f123f60905
commit f9f2bc8b83
2 changed files with 138 additions and 18 deletions

View file

@ -309,7 +309,15 @@ func (c *Client) updateMessageContent(update *client.UpdateMessageContent) {
}
log.Infof("ignoredResource: %v", ignoredResource)
jids := c.getCarbonFullJids(true, ignoredResource)
chat, _, _ := c.GetContactByID(update.ChatId, nil)
isMUC := c.Session.MUC && c.IsGroup(chat)
var jids []string
if isMUC {
_, jids = c.getMUCJoinedJIDs(update.ChatId)
} else {
c.getCarbonFullJids(true, ignoredResource)
}
if len(jids) == 0 {
log.Info("The only resource is ignored, aborting")
return
@ -342,7 +350,7 @@ func (c *Client) updateMessageContent(update *client.UpdateMessageContent) {
})
var prefix string
if messageErr == nil {
isCarbon = c.isCarbonsEnabled() && message.IsOutgoing
isCarbon = c.isCarbonsEnabled() && message.IsOutgoing && !isMUC
// reply correction support in clients is suboptimal yet, so cut them out for now
prefix, _ = c.messageToPrefix(message, "", "", true)
} else {
@ -370,9 +378,23 @@ func (c *Client) updateMessageContent(update *client.UpdateMessageContent) {
markupFunction,
))
sChatId := strconv.FormatInt(update.ChatId, 10)
var from string
var originalFrom string
if isMUC {
var nickname string
if messageErr == nil {
senderId := c.getMessageSenderId(message)
nickname = c.GetMUCNickname(senderId)
originalFrom = gateway.CHATJID(senderId, true)
} else {
nickname = "#ERROR#"
}
from = gateway.MUCJID(update.ChatId) + "/" + nickname
} else {
from = gateway.CHATNODE(update.ChatId)
}
for _, jid := range jids {
gateway.SendMessage(jid, sChatId, text.String(), "e"+sId, c.xmpp, nil, 0, replaceId, isCarbon, false, false, "")
gateway.SendMessage(jid, from, text.String(), "e"+sId, c.xmpp, nil, 0, replaceId, isCarbon, isMUC, false, originalFrom)
}
}
}

View file

@ -585,6 +585,47 @@ func (c *Client) sendMUCStatuses(chatID int64) {
)
}
func (c *Client) mucCacheHasMember(mucID int64, memberID int64) bool {
c.locks.mucCacheLock.Lock()
defer c.locks.mucCacheLock.Unlock()
mucState, ok := c.mucCache[mucID]
if !ok || mucState == nil {
return false // no MUC to be added to
}
_, ok = mucState.Members[memberID]
return ok
}
func (c *Client) addMUCMember(mucID int64, memberID int64, affiliation string) bool {
c.locks.mucCacheLock.Lock()
defer c.locks.mucCacheLock.Unlock()
mucState, ok := c.mucCache[mucID]
if !ok || mucState == nil {
return false
}
nickname := c.GetMUCNickname(memberID)
err := c.sendPresence(
gateway.SPFrom(gateway.MUCNODE(mucID)),
gateway.SPResource(nickname),
gateway.SPImmed(true),
gateway.SPMUCAffiliation(affiliation),
gateway.SPMUCJid(gateway.CHATJID(memberID, true)),
)
if err == nil {
mucState.Members[memberID] = &MUCMember{
Nickname: nickname,
Affiliation: affiliation,
}
return true
}
return false
}
func (c *Client) sendMUCSubject(chatID int64, resource string) {
pin, err := c.client.GetChatPinnedMessage(&client.GetChatPinnedMessageRequest{
ChatId: chatID,
@ -665,6 +706,24 @@ func (c *Client) MUCHasResource(chatID int64, resource string) bool {
return ok
}
func (c *Client) getMUCJoinedJIDs(chatId int64) (bool, []string) {
c.locks.mucCacheLock.Lock()
defer c.locks.mucCacheLock.Unlock()
groupChatTos := []string{}
mucState, ok := c.mucCache[chatId]
if !ok || mucState == nil {
return false, nil
} else {
for resource := range mucState.Resources {
groupChatTos = append(groupChatTos, c.jid + "/" + resource)
}
}
return true, groupChatTos
}
// GetMyMUCNickname obtains this account's nickname in a given MUC
func (c *Client) GetMyMUCNickname(chatID int64) (string, bool) {
if c.me == nil {
@ -1424,7 +1483,44 @@ func (c *Client) getPrefixSeparator(chatId int64) string {
// ProcessIncomingMessage is a legacy wrapper for SendMessageToGateway aiming only PM messages
func (c *Client) ProcessIncomingMessage(chatId int64, message *client.Message) {
c.SendMessageToGateway(chatId, message, "", false, "", []string{})
chat, _, _ := c.GetContactByID(chatId, nil)
safeToSend := true
groupChatFrom := ""
groupChatTos := []string{}
if c.Session.MUC && c.IsGroup(chat) {
senderId := c.getMessageSenderId(message)
if senderId == 0 {
log.Errorf("Invalid sender id for message %#v", message)
return
}
if !c.mucCacheHasMember(chatId, senderId) {
chatMember, err := c.client.GetChatMember(&client.GetChatMemberRequest{
ChatId: chatId,
MemberId: message.SenderId,
})
var status client.ChatMemberStatus
if err == nil {
status = chatMember.Status
}
safeToSend = c.addMUCMember(chatId, senderId, c.memberStatusToAffiliation(status))
}
groupChatFrom = gateway.MUCJID(chatId) + "/" + c.GetMUCNickname(senderId)
var ok bool
ok, groupChatTos = c.getMUCJoinedJIDs(chatId)
if !ok {
safeToSend = false
}
}
if safeToSend {
c.SendMessageToGateway(chatId, message, "", false, groupChatFrom, groupChatTos)
} else {
mucJID := gateway.MUCJID(chatId)
for _, to := range groupChatTos {
gateway.SendErrorMessage(to, mucJID, "Cannot show a message", 500, true, c.xmpp)
}
}
}
// SendMessageToGateway transfers a message to XMPP side and marks it as read on Telegram side
@ -2218,19 +2314,21 @@ func (c *Client) usernamesToString(usernames []string) string {
}
func (c *Client) memberStatusToAffiliation(memberStatus client.ChatMemberStatus) string {
switch memberStatus.ChatMemberStatusType() {
case client.TypeChatMemberStatusCreator:
return "owner"
case client.TypeChatMemberStatusAdministrator:
return "admin"
case client.TypeChatMemberStatusMember:
return "member"
case client.TypeChatMemberStatusRestricted:
return "outcast"
case client.TypeChatMemberStatusLeft:
return "none"
case client.TypeChatMemberStatusBanned:
return "outcast"
if memberStatus != nil {
switch memberStatus.ChatMemberStatusType() {
case client.TypeChatMemberStatusCreator:
return "owner"
case client.TypeChatMemberStatusAdministrator:
return "admin"
case client.TypeChatMemberStatusMember:
return "member"
case client.TypeChatMemberStatusRestricted:
return "outcast"
case client.TypeChatMemberStatusLeft:
return "none"
case client.TypeChatMemberStatusBanned:
return "outcast"
}
}
return "member"
}