Add legacy-to-MUC migrator

This commit is contained in:
Bohdan Horbeshko 2025-05-09 00:07:55 -04:00
parent 0500b3535f
commit a05724b93a
5 changed files with 73 additions and 10 deletions

View file

@ -463,6 +463,9 @@ func (c *Client) ProcessTransportCommand(cmdline string, resource string) (strin
if err != nil {
return err.Error(), false
}
if args[0] == "muc" && args[1] == "true" {
go c.MigrateToMUCs()
}
gateway.DirtySessions = true
return fmt.Sprintf("%s set to %s", args[0], value), true

View file

@ -2351,3 +2351,13 @@ func (c *Client) GetChatMembers(chatID int64, limited bool, query string, member
}
return members, nil
}
// MigrateToMUCs unsubscribes from legacy group chats and invites to MUCs
func (c *Client) MigrateToMUCs() {
for _, chat := range c.GetGroupChats() {
c.unsubscribe(chat.Id)
for resource := range c.resourcesRange() {
gateway.InviteToMUC(chat.Id, c.jid+"/"+resource, c.xmpp)
}
}
}

View file

@ -213,6 +213,27 @@ type QueryRegisterRemove struct {
XMLName xml.Name `xml:"remove"`
}
// MessageXMucUserExtension is from XEP-0045
type MessageXMucUserExtension struct {
XMLName xml.Name `xml:"http://jabber.org/protocol/muc#user x"`
Invite MessageXMucUserInvite
Password string `xml:"password,omitempty"`
}
// MessageXMucUserInvite is from XEP-0045
type MessageXMucUserInvite struct {
XMLName xml.Name `xml:"invite"`
From string `xml:"from,attr"`
Reason string `xml:"reason,omitempty"`
Continue MessageXMucUserInviteContinue
}
// MessageXMucUserInviteContinue is from XEP-0045
type MessageXMucUserInviteContinue struct {
XMLName xml.Name `xml:"continue"`
Thread string `xml:"thread,attr,omitempty"`
}
// PresenceXMucUserExtension is from XEP-0045
type PresenceXMucUserExtension struct {
XMLName xml.Name `xml:"http://jabber.org/protocol/muc#user x"`
@ -432,6 +453,12 @@ func init() {
"query",
}, QueryRegister{})
// message muc user
stanza.TypeRegistry.MapExtension(stanza.PKTMessage, xml.Name{
"http://jabber.org/protocol/muc#user",
"x",
}, MessageXMucUserExtension{})
// presence muc user
stanza.TypeRegistry.MapExtension(stanza.PKTPresence, xml.Name{
"http://jabber.org/protocol/muc#user",

View file

@ -63,7 +63,7 @@ var MessageOutgoingPermissionVersion = 0
// SendMessage creates and sends a message stanza
func SendMessage(to, from, body, id string, component *xmpp.Component, reply *Reply, timestamp int64, replaceId string, isCarbon, isGroupchat, requestReceipt bool, originalFrom string) {
sendMessageWrapper(to, from, body, "", "", id, component, reply, nil, timestamp, "", replaceId, isCarbon, isGroupchat, false, requestReceipt, originalFrom, 0)
sendMessageWrapper(to, from, body, "", "", id, component, reply, nil, timestamp, "", replaceId, isCarbon, isGroupchat, false, requestReceipt, originalFrom, 0, "")
}
// SendServiceMessage creates and sends a simple message stanza from transport
@ -72,7 +72,7 @@ func SendServiceMessage(to, body string, component *xmpp.Component) {
if uuid, err := uuid.NewRandom(); err == nil {
id = uuid.String()
}
sendMessageWrapper(to, "", body, "", "", id, component, nil, nil, 0, "", "", false, false, false, false, "", 0)
sendMessageWrapper(to, "", body, "", "", id, component, nil, nil, 0, "", "", false, false, false, false, "", 0, "")
}
// SendTextMessage creates and sends a simple message stanza
@ -81,27 +81,27 @@ func SendTextMessage(to, from, body string, component *xmpp.Component) {
if uuid, err := uuid.NewRandom(); err == nil {
id = uuid.String()
}
sendMessageWrapper(to, from, body, "", "", id, component, nil, nil, 0, "", "", false, false, false, false, "", 0)
sendMessageWrapper(to, from, body, "", "", id, component, nil, nil, 0, "", "", false, false, false, false, "", 0, "")
}
// SendErrorMessage creates and sends an error message stanza
func SendErrorMessage(to, from, text string, code int, isGroupchat bool, component *xmpp.Component) {
sendMessageWrapper(to, from, "", "", text, "", component, nil, nil, 0, "", "", false, isGroupchat, false, false, "", code)
sendMessageWrapper(to, from, "", "", text, "", component, nil, nil, 0, "", "", false, isGroupchat, false, false, "", code, "")
}
// SendErrorMessageWithBody creates and sends an error message stanza with body payload
func SendErrorMessageWithBody(to, from, body, errorText, id string, code int, isGroupchat bool, component *xmpp.Component) {
sendMessageWrapper(to, from, body, "", errorText, id, component, nil, nil, 0, "", "", false, isGroupchat, false, false, "", code)
sendMessageWrapper(to, from, body, "", errorText, id, component, nil, nil, 0, "", "", false, isGroupchat, false, false, "", code, "")
}
// SendMessageWithOOB creates and sends a message stanza with OOB URL
func SendMessageWithOOB(to, from, body, id string, component *xmpp.Component, reply *Reply, timestamp int64, oob, replaceId string, isCarbon, isGroupchat, requestReceipt bool, originalFrom string) {
sendMessageWrapper(to, from, body, "", "", id, component, reply, nil, timestamp, oob, replaceId, isCarbon, isGroupchat, false, requestReceipt, originalFrom, 0)
sendMessageWrapper(to, from, body, "", "", id, component, reply, nil, timestamp, oob, replaceId, isCarbon, isGroupchat, false, requestReceipt, originalFrom, 0, "")
}
// SendSubjectMessage creates and sends a MUC subject
func SendSubjectMessage(to, from, subject, id string, component *xmpp.Component, timestamp int64) {
sendMessageWrapper(to, from, "", subject, "", id, component, nil, nil, timestamp, "", "", false, true, true, false, "", 0)
sendMessageWrapper(to, from, "", subject, "", id, component, nil, nil, timestamp, "", "", false, true, true, false, "", 0, "")
}
// SendMessageMarker creates and sends a message stanza with a XEP-0333 marker
@ -109,10 +109,15 @@ func SendMessageMarker(to string, from string, component *xmpp.Component, marker
sendMessageWrapper(to, from, "", "", "", "", component, nil, &marker{
Type: markerType,
Id: markerId,
}, 0, "", "", false, false, false, false, "", 0)
}, 0, "", "", false, false, false, false, "", 0, "")
}
func sendMessageWrapper(to, from, body, subject, errorText, id string, component *xmpp.Component, reply *Reply, marker *marker, timestamp int64, oob, replaceId string, isCarbon, isGroupchat, forceSubject, requestReceipt bool, originalFrom string, errorCode int) {
// SendMUCInvite creates and send a MUC invitation message
func SendMUCInvite(to string, from string, component *xmpp.Component, inviteFrom string) {
sendMessageWrapper(to, from, "", "", "", "", component, nil, nil, 0, "", "", false, false, false, false, "", 0, inviteFrom)
}
func sendMessageWrapper(to, from, body, subject, errorText, id string, component *xmpp.Component, reply *Reply, marker *marker, timestamp int64, oob, replaceId string, isCarbon, isGroupchat, forceSubject, requestReceipt bool, originalFrom string, errorCode int, inviteFrom string) {
toJid, err := stanza.NewJid(to)
if err != nil {
log.WithFields(log.Fields{
@ -134,6 +139,9 @@ func sendMessageWrapper(to, from, body, subject, errorText, id string, component
if from == "" {
logFrom = componentJid
messageFrom = componentJid
} else if inviteFrom != "" {
logFrom = from
messageFrom = from + "@" + Jid.Bare()
} else {
logFrom = from
messageFrom = from + "@" + componentJid
@ -212,7 +220,7 @@ func sendMessageWrapper(to, from, body, subject, errorText, id string, component
message.Extensions = append(message.Extensions, extensions.NewReplyFallback(reply.Start, reply.End))
}
}
if !isGroupchat && !isCarbon && toJid.Resource != "" {
if !isGroupchat && !isCarbon && toJid.Resource != "" && inviteFrom == "" {
message.Extensions = append(message.Extensions, stanza.HintNoCopy{})
}
if timestamp != 0 {
@ -256,6 +264,13 @@ func sendMessageWrapper(to, from, body, subject, errorText, id string, component
if replaceId != "" {
message.Extensions = append(message.Extensions, extensions.Replace{Id: replaceId})
}
if inviteFrom != "" {
message.Extensions = append(message.Extensions, extensions.MessageXMucUserExtension{
Invite: extensions.MessageXMucUserInvite{
From: inviteFrom,
},
})
}
if isCarbon {
carbonMessage := extensions.ClientMessage{
@ -616,3 +631,8 @@ func SendPubSubAvatarNotification(component *xmpp.Component, jid string, chatId
_ = ResumableSend(component, message)
}
func InviteToMUC(chatID int64, jid string, component *xmpp.Component) {
sChatID := strconv.FormatInt(chatID, 10)
SendMUCInvite(jid, sChatID, component, Jid.Full())
}

View file

@ -1137,6 +1137,9 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
errString = fmt.Sprintf("Error for field %v: %v, aborting", field.Var, err.Error())
break
}
if field.Var == "muc" && fieldValue == "true" {
go session.MigrateToMUCs()
}
infoStrings = append(infoStrings, fmt.Sprintf("%s set to %s", field.Var, value))
gateway.DirtySessions = true
}