Browse Source

Add handling for group metadata changes and refactor things

Group metadata temporarily broken until power level bridging is implemented
Tulir Asokan 6 years ago
parent
commit
d3a178ecf3

+ 4 - 4
ROADMAP.md

@@ -37,10 +37,10 @@
     * [ ] Join
     * [ ] Leave
     * [ ] Kick
-  * [ ] Group metadata changes
-    * [ ] Title
-    * [ ] Avatar
-    * [ ] Description
+  * [x] Group metadata changes
+    * [x] Title
+    * [x] Avatar
+    * [x] Description
   * [x] Initial group metadata
   * [ ] User metadata changes
     * [ ] Display name

+ 1 - 1
database/message.go

@@ -87,7 +87,7 @@ func (msg *Message) Scan(row Scannable) *Message {
 	err := row.Scan(&msg.Owner, &msg.JID, &msg.MXID)
 	if err != nil {
 		if err != sql.ErrNoRows {
-			msg.log.Fatalln("Database scan failed:", err)
+			msg.log.Errorln("Database scan failed:", err)
 		}
 		return nil
 	}

+ 4 - 4
database/portal.go

@@ -33,9 +33,9 @@ func (pq *PortalQuery) CreateTable() error {
 		owner VARCHAR(255),
 		mxid  VARCHAR(255) UNIQUE,
 
-		name   VARCHAR(255),
-		topic  VARCHAR(255),
-		avatar VARCHAR(255),
+		name   VARCHAR(255) NOT NULL,
+		topic  VARCHAR(255) NOT NULL,
+		avatar VARCHAR(255) NOT NULL,
 
 		PRIMARY KEY (jid, owner),
 		FOREIGN KEY (owner) REFERENCES user(mxid)
@@ -95,7 +95,7 @@ func (portal *Portal) Scan(row Scannable) *Portal {
 	err := row.Scan(&portal.JID, &portal.Owner, &portal.MXID, &portal.Name, &portal.Topic, &portal.Avatar)
 	if err != nil {
 		if err != sql.ErrNoRows {
-			portal.log.Fatalln("Database scan failed:", err)
+			portal.log.Errorln("Database scan failed:", err)
 		}
 		return nil
 	}

+ 1 - 1
database/puppet.go

@@ -82,7 +82,7 @@ func (puppet *Puppet) Scan(row Scannable) *Puppet {
 	err := row.Scan(&puppet.JID, &puppet.Receiver, &puppet.Displayname, &puppet.Avatar)
 	if err != nil {
 		if err != sql.ErrNoRows {
-			puppet.log.Fatalln("Database scan failed:", err)
+			puppet.log.Errorln("Database scan failed:", err)
 		}
 		return nil
 	}

+ 1 - 1
database/user.go

@@ -86,7 +86,7 @@ func (user *User) Scan(row Scannable) *User {
 		&sess.EncKey, &sess.MacKey, &sess.Wid)
 	if err != nil {
 		if err != sql.ErrNoRows {
-			user.log.Fatalln("Database scan failed:", err)
+			user.log.Errorln("Database scan failed:", err)
 		}
 		return nil
 	}

+ 1 - 1
formatting.go

@@ -78,7 +78,7 @@ func (user *User) newWhatsAppFormatMaps() (map[*regexp.Regexp]string, map[*regex
 			return fmt.Sprintf("<code>%s</code>", str)
 		},
 		mentionRegex: func(str string) string {
-			jid := str[1:] + whatsapp_ext.NewUserSuffix
+			jid := str[1:] + whatsappExt.NewUserSuffix
 			puppet := user.GetPuppetByJID(jid)
 			return fmt.Sprintf(`<a href="https://matrix.to/#/%s">%s</a>`, puppet.MXID, puppet.Displayname)
 		},

+ 26 - 19
portal.go

@@ -118,19 +118,24 @@ type Portal struct {
 	roomCreateLock sync.Mutex
 }
 
-func (portal *Portal) SyncParticipants(metadata *whatsapp_ext.GroupInfo) {
+func (portal *Portal) SyncParticipants(metadata *whatsappExt.GroupInfo) {
 	for _, participant := range metadata.Participants {
 		intent := portal.user.GetPuppetByJID(participant.JID).Intent()
 		intent.EnsureJoined(portal.MXID)
+		// TODO set power levels
 	}
 }
 
-func (portal *Portal) UpdateAvatar() bool {
-	avatar, err := portal.user.Conn.GetProfilePicThumb(portal.JID)
-	if err != nil {
-		portal.log.Errorln(err)
-		return false
+func (portal *Portal) UpdateAvatar(avatar *whatsappExt.ProfilePicInfo) bool {
+	if avatar == nil {
+		var err error
+		avatar, err = portal.user.Conn.GetProfilePicThumb(portal.JID)
+		if err != nil {
+			portal.log.Errorln(err)
+			return false
+		}
 	}
+
 	if portal.Avatar == avatar.Tag {
 		return false
 	}
@@ -157,11 +162,12 @@ func (portal *Portal) UpdateAvatar() bool {
 	return true
 }
 
-func (portal *Portal) UpdateName(metadata *whatsapp_ext.GroupInfo) bool {
-	if portal.Name != metadata.Name {
-		_, err := portal.MainIntent().SetRoomName(portal.MXID, metadata.Name)
+func (portal *Portal) UpdateName(name string, setBy types.WhatsAppID) bool {
+	if portal.Name != name {
+		intent := portal.user.GetPuppetByJID(setBy).Intent()
+		_, err := intent.SetRoomName(portal.MXID, name)
 		if err == nil {
-			portal.Name = metadata.Name
+			portal.Name = name
 			return true
 		}
 		portal.log.Warnln("Failed to set room name:", err)
@@ -169,11 +175,12 @@ func (portal *Portal) UpdateName(metadata *whatsapp_ext.GroupInfo) bool {
 	return false
 }
 
-func (portal *Portal) UpdateTopic(metadata *whatsapp_ext.GroupInfo) bool {
-	if portal.Topic != metadata.Topic {
-		_, err := portal.MainIntent().SetRoomTopic(portal.MXID, metadata.Topic)
+func (portal *Portal) UpdateTopic(topic string, setBy types.WhatsAppID) bool {
+	if portal.Topic != topic {
+		intent := portal.user.GetPuppetByJID(setBy).Intent()
+		_, err := intent.SetRoomTopic(portal.MXID, topic)
 		if err == nil {
-			portal.Topic = metadata.Topic
+			portal.Topic = topic
 			return true
 		}
 		portal.log.Warnln("Failed to set room topic:", err)
@@ -189,8 +196,8 @@ func (portal *Portal) UpdateMetadata() bool {
 	}
 	portal.SyncParticipants(metadata)
 	update := false
-	update = portal.UpdateName(metadata) || update
-	update = portal.UpdateTopic(metadata) || update
+	update = portal.UpdateName(metadata.Name, metadata.NameSetBy) || update
+	update = portal.UpdateTopic(metadata.Topic, metadata.TopicSetBy) || update
 	return update
 }
 
@@ -212,7 +219,7 @@ func (portal *Portal) Sync(contact whatsapp.Contact) {
 
 	update := false
 	update = portal.UpdateMetadata() || update
-	update = portal.UpdateAvatar() || update
+	update = portal.UpdateAvatar(nil) || update
 	if update {
 		portal.Update()
 	}
@@ -251,7 +258,7 @@ func (portal *Portal) CreateMatrixRoom() error {
 }
 
 func (portal *Portal) IsPrivateChat() bool {
-	return strings.HasSuffix(portal.JID, whatsapp_ext.NewUserSuffix)
+	return strings.HasSuffix(portal.JID, whatsappExt.NewUserSuffix)
 }
 
 func (portal *Portal) MainIntent() *appservice.IntentAPI {
@@ -589,7 +596,7 @@ func (portal *Portal) HandleMatrixMessage(evt *gomatrix.Event) {
 		}
 		ctxInfo.MentionedJid = mentionRegex.FindAllString(text, -1)
 		for index, mention := range ctxInfo.MentionedJid {
-			ctxInfo.MentionedJid[index] = mention[1:] + whatsapp_ext.NewUserSuffix
+			ctxInfo.MentionedJid[index] = mention[1:] + whatsappExt.NewUserSuffix
 		}
 		if ctxInfo.StanzaId != nil || ctxInfo.MentionedJid != nil {
 			info.Message.ExtendedTextMessage = &waProto.ExtendedTextMessage{

+ 4 - 4
puppet.go

@@ -47,7 +47,7 @@ func (bridge *Bridge) ParsePuppetMXID(mxid types.MatrixUserID) (types.MatrixUser
 	receiver = strings.Replace(receiver, "=40", "@", 1)
 	colonIndex := strings.LastIndex(receiver, "=3")
 	receiver = receiver[:colonIndex] + ":" + receiver[colonIndex+len("=3"):]
-	jid := types.WhatsAppID(match[2] + whatsapp_ext.NewUserSuffix)
+	jid := types.WhatsAppID(match[2] + whatsappExt.NewUserSuffix)
 	return receiver, jid, true
 }
 
@@ -120,7 +120,7 @@ func (user *User) NewPuppet(dbPuppet *database.Puppet) *Puppet {
 				dbPuppet.Receiver,
 				strings.Replace(
 					dbPuppet.JID,
-					whatsapp_ext.NewUserSuffix, "", 1)),
+					whatsappExt.NewUserSuffix, "", 1)),
 			user.bridge.Config.Homeserver.Domain),
 	}
 }
@@ -139,14 +139,14 @@ type Puppet struct {
 }
 
 func (puppet *Puppet) PhoneNumber() string {
-	return strings.Replace(puppet.JID, whatsapp_ext.NewUserSuffix, "", 1)
+	return strings.Replace(puppet.JID, whatsappExt.NewUserSuffix, "", 1)
 }
 
 func (puppet *Puppet) Intent() *appservice.IntentAPI {
 	return puppet.bridge.AppService.Intent(puppet.MXID)
 }
 
-func (puppet *Puppet) UpdateAvatar(avatar *whatsapp_ext.ProfilePicInfo) bool {
+func (puppet *Puppet) UpdateAvatar(avatar *whatsappExt.ProfilePicInfo) bool {
 	if avatar == nil {
 		var err error
 		avatar, err = puppet.user.Conn.GetProfilePicThumb(puppet.JID)

+ 6 - 0
statestore.go

@@ -17,6 +17,7 @@
 package main
 
 import (
+	"maunium.net/go/gomatrix"
 	"maunium.net/go/mautrix-appservice"
 	"encoding/json"
 	"io/ioutil"
@@ -65,3 +66,8 @@ func (store *AutosavingStateStore) SetMembership(roomID, userID, membership stri
 	store.BasicStateStore.SetMembership(roomID, userID, membership)
 	store.Save()
 }
+
+func (store *AutosavingStateStore) SetPowerLevels(roomID string, levels gomatrix.PowerLevels) {
+	store.BasicStateStore.SetPowerLevels(roomID, levels)
+	store.Save()
+}

+ 40 - 14
user.go

@@ -33,7 +33,7 @@ import (
 
 type User struct {
 	*database.User
-	Conn *whatsapp_ext.ExtendedConn
+	Conn *whatsappExt.ExtendedConn
 
 	bridge *Bridge
 	log    log.Logger
@@ -134,7 +134,7 @@ func (user *User) Connect(evenIfNoSession bool) bool {
 		user.log.Errorln("Failed to connect to WhatsApp:", err)
 		return false
 	}
-	user.Conn = whatsapp_ext.ExtendConn(conn)
+	user.Conn = whatsappExt.ExtendConn(conn)
 	user.log.Debugln("WhatsApp connection successful")
 	user.Conn.AddHandler(user)
 	return user.RestoreSession()
@@ -194,14 +194,14 @@ func (user *User) Login(roomID types.MatrixRoomID) {
 }
 
 func (user *User) JID() string {
-	return strings.Replace(user.Conn.Info.Wid, whatsapp_ext.OldUserSuffix, whatsapp_ext.NewUserSuffix, 1)
+	return strings.Replace(user.Conn.Info.Wid, whatsappExt.OldUserSuffix, whatsappExt.NewUserSuffix, 1)
 }
 
 func (user *User) Sync() {
 	user.log.Debugln("Syncing...")
 	user.Conn.Contacts()
 	for jid, contact := range user.Conn.Store.Contacts {
-		if strings.HasSuffix(jid, whatsapp_ext.NewUserSuffix) {
+		if strings.HasSuffix(jid, whatsappExt.NewUserSuffix) {
 			puppet := user.GetPuppetByJID(contact.Jid)
 			puppet.Sync(contact)
 		}
@@ -249,12 +249,12 @@ func (user *User) HandleDocumentMessage(message whatsapp.DocumentMessage) {
 	portal.HandleMediaMessage(message.Download, message.Thumbnail, message.Info, message.Type, message.Title)
 }
 
-func (user *User) HandlePresence(info whatsapp_ext.Presence) {
+func (user *User) HandlePresence(info whatsappExt.Presence) {
 	puppet := user.GetPuppetByJID(info.SenderJID)
 	switch info.Status {
-	case whatsapp_ext.PresenceUnavailable:
+	case whatsappExt.PresenceUnavailable:
 		puppet.Intent().SetPresence("offline")
-	case whatsapp_ext.PresenceAvailable:
+	case whatsappExt.PresenceAvailable:
 		if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() {
 			puppet.Intent().UserTyping(puppet.typingIn, false, 0)
 			puppet.typingIn = ""
@@ -262,7 +262,7 @@ func (user *User) HandlePresence(info whatsapp_ext.Presence) {
 		} else {
 			puppet.Intent().SetPresence("online")
 		}
-	case whatsapp_ext.PresenceComposing:
+	case whatsappExt.PresenceComposing:
 		portal := user.GetPortalByJID(info.JID)
 		puppet.typingIn = portal.MXID
 		puppet.typingAt = time.Now().Unix()
@@ -270,8 +270,8 @@ func (user *User) HandlePresence(info whatsapp_ext.Presence) {
 	}
 }
 
-func (user *User) HandleMsgInfo(info whatsapp_ext.MsgInfo) {
-	if (info.Command == whatsapp_ext.MsgInfoCommandAck || info.Command == whatsapp_ext.MsgInfoCommandAcks) && info.Acknowledgement == whatsapp_ext.AckMessageRead {
+func (user *User) HandleMsgInfo(info whatsappExt.MsgInfo) {
+	if (info.Command == whatsappExt.MsgInfoCommandAck || info.Command == whatsappExt.MsgInfoCommandAcks) && info.Acknowledgement == whatsappExt.AckMessageRead {
 		portal := user.GetPortalByJID(info.ToJID)
 		if len(portal.MXID) == 0 {
 			return
@@ -291,11 +291,37 @@ func (user *User) HandleMsgInfo(info whatsapp_ext.MsgInfo) {
 	}
 }
 
-func (user *User) HandleCommand(cmd whatsapp_ext.Command) {
+func (user *User) HandleCommand(cmd whatsappExt.Command) {
 	switch cmd.Type {
-	case whatsapp_ext.CommandPicture:
-		puppet := user.GetPuppetByJID(cmd.JID)
-		puppet.UpdateAvatar(cmd.ProfilePicInfo)
+	case whatsappExt.CommandPicture:
+		if strings.HasSuffix(cmd.JID, whatsappExt.NewUserSuffix) {
+			puppet := user.GetPuppetByJID(cmd.JID)
+			puppet.UpdateAvatar(cmd.ProfilePicInfo)
+		} else {
+			portal := user.GetPortalByJID(cmd.JID)
+			portal.UpdateAvatar(cmd.ProfilePicInfo)
+		}
+	}
+}
+
+func (user *User) HandleChatUpdate(cmd whatsappExt.ChatUpdate) {
+	if cmd.Command != whatsappExt.ChatUpdateCommandAction {
+		return
+	}
+
+	portal := user.GetPortalByJID(cmd.JID)
+	if len(portal.MXID) == 0 {
+		return
+	}
+
+	switch cmd.Data.Action {
+	case whatsappExt.ChatActionNameChange:
+		portal.UpdateName(cmd.Data.NameChange.Name, cmd.Data.SenderJID)
+	case whatsappExt.ChatActionAddTopic:
+		portal.UpdateTopic(cmd.Data.AddTopic.Topic, cmd.Data.SenderJID)
+	case whatsappExt.ChatActionRemoveTopic:
+		portal.UpdateTopic("", cmd.Data.SenderJID)
+	// TODO power level updates
 	}
 }
 

+ 144 - 0
whatsapp-ext/chat.go

@@ -0,0 +1,144 @@
+// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
+// Copyright (C) 2018 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+package whatsappExt
+
+import (
+	"encoding/json"
+	"strings"
+
+	"github.com/Rhymen/go-whatsapp"
+)
+
+type ChatUpdateCommand string
+
+const (
+	ChatUpdateCommandAction ChatUpdateCommand = "action"
+)
+
+type ChatUpdate struct {
+	JID     string            `json:"id"`
+	Command ChatUpdateCommand `json:"cmd"`
+	Data    ChatUpdateData    `json:"data"`
+}
+
+type ChatActionType string
+
+const (
+	ChatActionNameChange  ChatActionType = "subject"
+	ChatActionAddTopic    ChatActionType = "desc_add"
+	ChatActionRemoveTopic ChatActionType = "desc_remove"
+	ChatActionRestrict    ChatActionType = "restrict"
+	ChatActionAnnounce    ChatActionType = "announce"
+	ChatActionPromote     ChatActionType = "promote"
+	ChatActionDemote      ChatActionType = "demote"
+)
+
+type ChatUpdateData struct {
+	Action    ChatActionType
+	SenderJID string
+
+	NameChange struct {
+		Name  string `json:"subject"`
+		SetAt int64  `json:"s_t"`
+		SetBy string `json:"s_o"`
+	}
+
+	AddTopic struct {
+		Topic string `json:"desc"`
+		ID    string `json:"descId"`
+		SetAt int64  `json:"descTime"`
+	}
+
+	RemoveTopic struct {
+		ID string `json:"descId"`
+	}
+
+	Restrict bool
+
+	Announce bool
+
+	PermissionChange struct {
+		JIDs []string `json:"participants"`
+	}
+}
+
+func (cud *ChatUpdateData) UnmarshalJSON(data []byte) error {
+	var arr []json.RawMessage
+	err := json.Unmarshal(data, &arr)
+	if err != nil {
+		return err
+	} else if len(arr) < 3 {
+		return nil
+	}
+
+	err = json.Unmarshal(arr[0], &cud.Action)
+	if err != nil {
+		return err
+	}
+
+	err = json.Unmarshal(arr[1], &cud.SenderJID)
+	if err != nil {
+		return err
+	}
+	cud.SenderJID = strings.Replace(cud.SenderJID, OldUserSuffix, NewUserSuffix, 1)
+
+	var unmarshalTo interface{}
+	switch cud.Action {
+	case ChatActionNameChange:
+		unmarshalTo = &cud.NameChange
+	case ChatActionAddTopic:
+		unmarshalTo = &cud.AddTopic
+	case ChatActionRemoveTopic:
+		unmarshalTo = &cud.RemoveTopic
+	case ChatActionRestrict:
+		unmarshalTo = &cud.Restrict
+	case ChatActionAnnounce:
+		unmarshalTo = &cud.Announce
+	case ChatActionPromote, ChatActionDemote:
+		unmarshalTo = &cud.PermissionChange
+	default:
+		return nil
+	}
+	err = json.Unmarshal(arr[2], unmarshalTo)
+	if err != nil {
+		return err
+	}
+	cud.NameChange.SetBy = strings.Replace(cud.NameChange.SetBy, OldUserSuffix, NewUserSuffix, 1)
+	return nil
+}
+
+type ChatUpdateHandler interface {
+	whatsapp.Handler
+	HandleChatUpdate(ChatUpdate)
+}
+
+func (ext *ExtendedConn) handleMessageChatUpdate(message []byte) {
+	var event ChatUpdate
+	err := json.Unmarshal(message, &event)
+	if err != nil {
+		ext.jsonParseError(err)
+		return
+	}
+	event.JID = strings.Replace(event.JID, OldUserSuffix, NewUserSuffix, 1)
+	for _, handler := range ext.handlers {
+		chatUpdateHandler, ok := handler.(ChatUpdateHandler)
+		if !ok {
+			continue
+		}
+		go chatUpdateHandler.HandleChatUpdate(event)
+	}
+}

+ 2 - 2
whatsapp-ext/cmd.go

@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-package whatsapp_ext
+package whatsappExt
 
 import (
 	"encoding/json"
@@ -41,7 +41,7 @@ type CommandHandler interface {
 	HandleCommand(Command)
 }
 
-func (ext *ExtendedConn) handleMessageCommand(msgType JSONMessageType, message []byte) {
+func (ext *ExtendedConn) handleMessageCommand(message []byte) {
 	var event Command
 	err := json.Unmarshal(message, &event)
 	if err != nil {

+ 1 - 1
whatsapp-ext/conn.go

@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-package whatsapp_ext
+package whatsappExt
 
 import (
 	"encoding/json"

+ 5 - 2
whatsapp-ext/jsonmessage.go

@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-package whatsapp_ext
+package whatsappExt
 
 import (
 	"encoding/json"
@@ -34,6 +34,7 @@ const (
 	MessageConn     JSONMessageType = "Conn"
 	MessageProps    JSONMessageType = "Props"
 	MessageCmd      JSONMessageType = "Cmd"
+	MessageChat     JSONMessageType = "Chat"
 )
 
 func (ext *ExtendedConn) AddHandler(handler whatsapp.Handler) {
@@ -85,7 +86,9 @@ func (ext *ExtendedConn) HandleJsonMessage(message string) {
 	case MessageMsgInfo, MessageMsg:
 		ext.handleMessageMsgInfo(msgType, msg[1])
 	case MessageCmd:
-		ext.handleMessageCommand(msgType, msg[1])
+		ext.handleMessageCommand(msg[1])
+	case MessageChat:
+		ext.handleMessageChatUpdate(msg[1])
 	default:
 		for _, handler := range ext.handlers {
 			ujmHandler, ok := handler.(UnhandledJSONMessageHandler)

+ 1 - 1
whatsapp-ext/msginfo.go

@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-package whatsapp_ext
+package whatsappExt
 
 import (
 	"encoding/json"

+ 1 - 1
whatsapp-ext/presence.go

@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-package whatsapp_ext
+package whatsappExt
 
 import (
 	"encoding/json"

+ 1 - 1
whatsapp-ext/props.go

@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-package whatsapp_ext
+package whatsappExt
 
 import (
 	"github.com/Rhymen/go-whatsapp"

+ 1 - 1
whatsapp-ext/stream.go

@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-package whatsapp_ext
+package whatsappExt
 
 import (
 	"encoding/json"

+ 3 - 1
whatsapp-ext/whatsapp.go

@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-package whatsapp_ext
+package whatsappExt
 
 import (
 	"fmt"
@@ -83,6 +83,8 @@ func (ext *ExtendedConn) GetGroupMetaData(jid string) (*GroupInfo, error) {
 	for index, participant := range info.Participants {
 		info.Participants[index].JID = strings.Replace(participant.JID, OldUserSuffix, NewUserSuffix, 1)
 	}
+	info.NameSetBy = strings.Replace(info.NameSetBy, OldUserSuffix, NewUserSuffix, 1)
+	info.TopicSetBy = strings.Replace(info.TopicSetBy, OldUserSuffix, NewUserSuffix, 1)
 
 	return info, nil
 }