Sync broadcast list recipients too

This commit is contained in:
Tulir Asokan 2021-02-21 14:45:33 +02:00
parent a911a0c1a9
commit ac2ca08007
4 changed files with 75 additions and 43 deletions

View file

@ -164,7 +164,7 @@ func (puppet *Puppet) ProcessResponse(resp *mautrix.RespSync, _ string) error {
}
for roomID, events := range resp.Rooms.Join {
portal := puppet.bridge.GetPortalByMXID(roomID)
if portal == nil {
if portal == nil || portal.IsBroadcastList() {
continue
}
for _, evt := range events.Ephemeral.Events {

2
go.mod
View file

@ -16,4 +16,4 @@ require (
maunium.net/go/mautrix v0.8.3
)
replace github.com/Rhymen/go-whatsapp => github.com/tulir/go-whatsapp v0.3.22-0.20210221121735-6d3eaaa7bdc5
replace github.com/Rhymen/go-whatsapp => github.com/tulir/go-whatsapp v0.3.22-0.20210221124355-8c89650e6a9e

2
go.sum
View file

@ -337,6 +337,8 @@ github.com/tulir/go-whatsapp v0.3.22-0.20210221000549-ec31478c7b94 h1:G4YvxLMW80
github.com/tulir/go-whatsapp v0.3.22-0.20210221000549-ec31478c7b94/go.mod h1:rwwuTh1bKqhgrRvOBAr8hDqtuz8Cc1Quqw/0BeXb+/E=
github.com/tulir/go-whatsapp v0.3.22-0.20210221121735-6d3eaaa7bdc5 h1:4Y5xQdpuLEt4DQavhnP/Ium1zpwIE+LeOFwVyiW4qoY=
github.com/tulir/go-whatsapp v0.3.22-0.20210221121735-6d3eaaa7bdc5/go.mod h1:rwwuTh1bKqhgrRvOBAr8hDqtuz8Cc1Quqw/0BeXb+/E=
github.com/tulir/go-whatsapp v0.3.22-0.20210221124355-8c89650e6a9e h1:jQGaSyVl7gx44KYH1UY9JnhoLAqTEKysIhLjQJZZKVY=
github.com/tulir/go-whatsapp v0.3.22-0.20210221124355-8c89650e6a9e/go.mod h1:rwwuTh1bKqhgrRvOBAr8hDqtuz8Cc1Quqw/0BeXb+/E=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=

112
portal.go
View file

@ -359,6 +359,43 @@ func (portal *Portal) finishHandling(source *User, message *waProto.WebMessageIn
portal.log.Debugln("Handled message", message.GetKey().GetId(), "->", mxid)
}
func (portal *Portal) kickExtraUsers(participantMap map[whatsapp.JID]bool) {
members, err := portal.MainIntent().JoinedMembers(portal.MXID)
if err != nil {
portal.log.Warnln("Failed to get member list:", err)
} else {
for member := range members.Joined {
jid, ok := portal.bridge.ParsePuppetMXID(member)
if ok {
_, shouldBePresent := participantMap[jid]
if !shouldBePresent {
_, err := portal.MainIntent().KickUser(portal.MXID, &mautrix.ReqKickUser{
UserID: member,
Reason: "User had left this WhatsApp chat",
})
if err != nil {
portal.log.Warnfln("Failed to kick user %s who had left: %v", member, err)
}
}
}
}
}
}
func (portal *Portal) SyncBroadcastRecipients(metadata *whatsapp.BroadcastListInfo) {
participantMap := make(map[whatsapp.JID]bool)
for _, recipient := range metadata.Recipients {
participantMap[recipient.JID] = true
puppet := portal.bridge.GetPuppetByJID(recipient.JID)
err := puppet.DefaultIntent().EnsureJoined(portal.MXID)
if err != nil {
portal.log.Warnfln("Failed to make puppet of %s join %s: %v", recipient.JID, portal.MXID, err)
}
}
portal.kickExtraUsers(participantMap)
}
func (portal *Portal) SyncParticipants(metadata *whatsapp.GroupInfo) {
changed := false
levels, err := portal.MainIntent().PowerLevels(portal.MXID)
@ -366,7 +403,7 @@ func (portal *Portal) SyncParticipants(metadata *whatsapp.GroupInfo) {
levels = portal.GetBasePowerLevels()
changed = true
}
participantMap := make(map[string]bool)
participantMap := make(map[whatsapp.JID]bool)
for _, participant := range metadata.Participants {
participantMap[participant.JID] = true
user := portal.bridge.GetUserByJID(participant.JID)
@ -395,26 +432,7 @@ func (portal *Portal) SyncParticipants(metadata *whatsapp.GroupInfo) {
portal.log.Errorln("Failed to change power levels:", err)
}
}
members, err := portal.MainIntent().JoinedMembers(portal.MXID)
if err != nil {
portal.log.Warnln("Failed to get member list:", err)
} else {
for member := range members.Joined {
jid, ok := portal.bridge.ParsePuppetMXID(member)
if ok {
_, shouldBePresent := participantMap[jid]
if !shouldBePresent {
_, err := portal.MainIntent().KickUser(portal.MXID, &mautrix.ReqKickUser{
UserID: member,
Reason: "User had left this WhatsApp chat",
})
if err != nil {
portal.log.Warnfln("Failed to kick user %s who had left: %v", member, err)
}
}
}
}
}
portal.kickExtraUsers(participantMap)
}
func (portal *Portal) UpdateAvatar(user *User, avatar *whatsapp.ProfilePicInfo, updateInfo bool) bool {
@ -469,7 +487,7 @@ func (portal *Portal) UpdateAvatar(user *User, avatar *whatsapp.ProfilePicInfo,
}
func (portal *Portal) UpdateName(name string, setBy whatsapp.JID, intent *appservice.IntentAPI, updateInfo bool) bool {
if name == "" && portal.IsBroadcastRoom() {
if name == "" && portal.IsBroadcastList() {
name = UnnamedBroadcastName
}
if portal.Name != name {
@ -522,12 +540,12 @@ func (portal *Portal) UpdateTopic(topic string, setBy whatsapp.JID, intent *apps
func (portal *Portal) UpdateMetadata(user *User) bool {
if portal.IsPrivateChat() {
return false
} else if portal.IsStatusBroadcastRoom() {
} else if portal.IsStatusBroadcastList() {
update := false
update = portal.UpdateName(StatusBroadcastName, "", nil, false) || update
update = portal.UpdateTopic(StatusBroadcastTopic, "", nil, false) || update
return update
} else if portal.IsBroadcastRoom() {
} else if portal.IsBroadcastList() {
update := false
contact, _ := user.Conn.Store.Contacts[portal.Key.JID]
update = portal.UpdateName(contact.Name, "", nil, false) || update
@ -612,7 +630,7 @@ func (portal *Portal) Sync(user *User, contact whatsapp.Contact) {
update := false
update = portal.UpdateMetadata(user) || update
if !portal.IsPrivateChat() && !portal.IsBroadcastRoom() && portal.Avatar == "" {
if !portal.IsPrivateChat() && !portal.IsBroadcastList() && portal.Avatar == "" {
update = portal.UpdateAvatar(user, nil, false) || update
}
if update {
@ -988,6 +1006,7 @@ func (portal *Portal) CreateMatrixRoom(user *User) error {
portal.log.Infoln("Creating Matrix room. Info source:", user.MXID)
var metadata *whatsapp.GroupInfo
var broadcastMetadata *whatsapp.BroadcastListInfo
if portal.IsPrivateChat() {
puppet := portal.bridge.GetPuppetByJID(portal.Key.JID)
if portal.bridge.Config.Bridge.PrivateChatPortalMeta {
@ -998,14 +1017,19 @@ func (portal *Portal) CreateMatrixRoom(user *User) error {
portal.Name = ""
}
portal.Topic = "WhatsApp private chat"
} else if portal.IsStatusBroadcastRoom() {
} else if portal.IsStatusBroadcastList() {
portal.Name = "WhatsApp Status Broadcast"
portal.Topic = "WhatsApp status updates from your contacts"
} else if portal.IsBroadcastRoom() {
contact, ok := user.Conn.Store.Contacts[portal.Key.JID]
if ok {
portal.Name = contact.Name
} else if portal.IsBroadcastList() {
var err error
broadcastMetadata, err = user.Conn.GetBroadcastMetadata(portal.Key.JID)
if err == nil && broadcastMetadata.Status == 0 {
portal.Name = broadcastMetadata.Name
} else {
contact, _ := user.Conn.Store.Contacts[portal.Key.JID]
portal.Name = contact.Name
}
if len(portal.Name) == 0 {
portal.Name = UnnamedBroadcastName
}
portal.Topic = BroadcastTopic
@ -1097,6 +1121,9 @@ func (portal *Portal) CreateMatrixRoom(user *User) error {
_ = customPuppet.CustomIntent().EnsureJoined(portal.MXID)
}
}
if broadcastMetadata != nil {
portal.SyncBroadcastRecipients(broadcastMetadata)
}
user.addPortalToCommunity(portal)
if portal.IsPrivateChat() {
puppet := user.bridge.GetPuppetByJID(portal.Key.JID)
@ -1126,7 +1153,7 @@ func (portal *Portal) IsPrivateChat() bool {
return *portal.isPrivate
}
func (portal *Portal) IsBroadcastRoom() bool {
func (portal *Portal) IsBroadcastList() bool {
if portal.isBroadcast == nil {
val := strings.HasSuffix(portal.Key.JID, whatsapp.BroadcastSuffix)
portal.isBroadcast = &val
@ -1134,7 +1161,7 @@ func (portal *Portal) IsBroadcastRoom() bool {
return *portal.isBroadcast
}
func (portal *Portal) IsStatusBroadcastRoom() bool {
func (portal *Portal) IsStatusBroadcastList() bool {
return portal.Key.JID == "status@broadcast"
}
@ -1310,8 +1337,9 @@ func (portal *Portal) HandleTextMessage(source *User, message whatsapp.TextMessa
}
func (portal *Portal) HandleStubMessage(source *User, message whatsapp.StubMessage, isBackfill bool) {
if portal.bridge.Config.Bridge.ChatMetaSync {
if portal.bridge.Config.Bridge.ChatMetaSync && (!portal.IsBroadcastList() || isBackfill) {
// Chat meta sync is enabled, so we use chat update commands and full-syncs instead of message history
// However, broadcast lists don't have update commands, so we handle these if it's not a backfill
return
}
intent := portal.startHandling(source, message.Info)
@ -1341,9 +1369,9 @@ func (portal *Portal) HandleStubMessage(source *User, message whatsapp.StubMessa
eventID = portal.RestrictMessageSending(message.FirstParam == "on")
case waProto.WebMessageInfo_GROUP_CHANGE_RESTRICT:
eventID = portal.RestrictMetadataChanges(message.FirstParam == "on")
case waProto.WebMessageInfo_GROUP_PARTICIPANT_ADD, waProto.WebMessageInfo_GROUP_PARTICIPANT_INVITE:
case waProto.WebMessageInfo_GROUP_PARTICIPANT_ADD, waProto.WebMessageInfo_GROUP_PARTICIPANT_INVITE, waProto.WebMessageInfo_BROADCAST_ADD:
portal.HandleWhatsAppInvite(senderJID, intent, message.Params)
case waProto.WebMessageInfo_GROUP_PARTICIPANT_REMOVE, waProto.WebMessageInfo_GROUP_PARTICIPANT_LEAVE:
case waProto.WebMessageInfo_GROUP_PARTICIPANT_REMOVE, waProto.WebMessageInfo_GROUP_PARTICIPANT_LEAVE, waProto.WebMessageInfo_BROADCAST_REMOVE:
portal.HandleWhatsAppKick(source, senderJID, message.Params)
case waProto.WebMessageInfo_GROUP_PARTICIPANT_PROMOTE:
eventID = portal.ChangeAdminStatus(message.Params, true)
@ -1525,13 +1553,15 @@ func (portal *Portal) HandleWhatsAppKick(source *User, senderJID string, jids []
puppet := portal.bridge.GetPuppetByJID(jid)
portal.removeUser(puppet.JID == sender.JID, senderIntent, puppet.MXID, puppet.DefaultIntent())
user := portal.bridge.GetUserByJID(jid)
if user != nil {
var customIntent *appservice.IntentAPI
if puppet.CustomMXID == user.MXID {
customIntent = puppet.CustomIntent()
if !portal.IsBroadcastList() {
user := portal.bridge.GetUserByJID(jid)
if user != nil {
var customIntent *appservice.IntentAPI
if puppet.CustomMXID == user.MXID {
customIntent = puppet.CustomIntent()
}
portal.removeUser(puppet.JID == sender.JID, senderIntent, user.MXID, customIntent)
}
portal.removeUser(puppet.JID == sender.JID, senderIntent, user.MXID, customIntent)
}
}
}