Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions pkg/connector/capabilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func (m *MetaConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities {
}

func (m *MetaConnector) GetBridgeInfoVersion() (info, caps int) {
return 1, 11
return 1, 12
}

const MaxTextLength = 20000
Expand All @@ -71,7 +71,7 @@ func supportedIfFFmpeg() event.CapabilitySupportLevel {
}

func capID() string {
base := "fi.mau.meta.capabilities.2025_11_25"
base := "fi.mau.meta.capabilities.2026_01_25"
if ffmpeg.Supported() {
return base + "+ffmpeg"
}
Expand Down Expand Up @@ -165,6 +165,7 @@ var metaCaps = &event.RoomFeatures{

var metaCapsWithThreads *event.RoomFeatures
var metaCapsWithE2E *event.RoomFeatures
var metaCapsWithE2EGroup *event.RoomFeatures
var igCaps *event.RoomFeatures
var igCapsGroup *event.RoomFeatures
var metaCapsGroup *event.RoomFeatures
Expand All @@ -186,13 +187,20 @@ func init() {
delete(metaCapsWithE2E.File[event.MsgVideo].MimeTypes, "video/webm")
delete(metaCapsWithE2E.File[event.MsgVideo].MimeTypes, "video/ogg")
metaCapsWithE2E.DeleteChat = false
metaCapsWithE2EGroup = metaCapsWithE2E.Clone()
metaCapsWithE2EGroup.ID += "+group"
metaCapsWithE2EGroup.MemberActions = map[event.MemberAction]event.CapabilitySupportLevel{
event.MemberActionInvite: event.CapLevelFullySupported,
event.MemberActionKick: event.CapLevelFullySupported,
}

metaCapsGroup = metaCaps.Clone()
metaCapsGroup.ID += "+group"
metaCapsGroup.State = event.StateFeatureMap{
event.StateRoomName.Type: {Level: event.CapLevelFullySupported},
event.StateRoomAvatar.Type: {Level: event.CapLevelFullySupported},
}
metaCapsGroup.MemberActions = metaCapsWithE2EGroup.MemberActions.Clone()

igCaps = metaCaps.Clone()
delete(igCaps.File, event.MsgFile)
Expand All @@ -205,14 +213,17 @@ func init() {
igCapsGroup.State = event.StateFeatureMap{
event.StateRoomName.Type: {Level: event.CapLevelFullySupported},
}
igCapsGroup.MemberActions = metaCapsWithE2EGroup.MemberActions.Clone()
}

func (m *MetaClient) GetCapabilities(ctx context.Context, portal *bridgev2.Portal) *event.RoomFeatures {
switch portal.Metadata.(*metaid.PortalMetadata).ThreadType {
case table.COMMUNITY_GROUP:
return metaCapsWithThreads
case table.ENCRYPTED_OVER_WA_ONE_TO_ONE, table.ENCRYPTED_OVER_WA_GROUP:
case table.ENCRYPTED_OVER_WA_ONE_TO_ONE:
return metaCapsWithE2E
case table.ENCRYPTED_OVER_WA_GROUP:
return metaCapsWithE2EGroup
}
if m.Client.GetPlatform() == types.Instagram || m.Main.Config.Mode == types.Instagram {
if portal.RoomType == database.RoomTypeDM {
Expand Down
66 changes: 66 additions & 0 deletions pkg/connector/handlematrix.go
Original file line number Diff line number Diff line change
Expand Up @@ -750,3 +750,69 @@ func (m *MetaClient) HandleMatrixRoomAvatar(ctx context.Context, msg *bridgev2.M
// TODO update portal metadata
return true, nil
}

func (m *MetaClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2.MatrixMembershipChange) (*bridgev2.MatrixMembershipResult, error) {
if msg.Portal.RoomType == database.RoomTypeDM {
return nil, errors.New("cannot change members for DM")
}

var targetID int64
switch target := msg.Target.(type) {
case *bridgev2.Ghost:
targetID = metaid.ParseUserID(target.ID)
case *bridgev2.UserLogin:
targetID = metaid.ParseUserLoginID(target.ID)
default:
return nil, fmt.Errorf("unknown membership target type %T", target)
}
if targetID == 0 {
return nil, fmt.Errorf("invalid target user ID")
}

portalMeta := msg.Portal.Metadata.(*metaid.PortalMetadata)
if portalMeta.ThreadType == table.ENCRYPTED_OVER_WA_GROUP {
portalJID := portalMeta.JID(msg.Portal.ID)
targetJID := waTypes.NewJID(strconv.FormatInt(targetID, 10), waTypes.MessengerServer)
var action whatsmeow.ParticipantChange
switch msg.Type {
case bridgev2.Invite:
action = whatsmeow.ParticipantChangeAdd
case bridgev2.Kick:
action = whatsmeow.ParticipantChangeRemove
default:
return nil, nil
}
resp, err := m.E2EEClient.UpdateGroupParticipants(ctx, portalJID, []waTypes.JID{targetJID}, action)
if err != nil {
return nil, err
} else if len(resp) == 0 {
return nil, fmt.Errorf("no response for participant change")
} else if resp[0].Error != 0 {
return nil, fmt.Errorf("failed to change participant: code %d", resp[0].Error)
}
return &bridgev2.MatrixMembershipResult{RedirectTo: metaid.MakeWAUserID(resp[0].JID)}, nil
}

threadID := metaid.ParseFBPortalID(msg.Portal.ID)
var task socket.Task
switch msg.Type {
case bridgev2.Invite:
task = &socket.AddParticipantsTask{
ThreadKey: threadID,
ContactIDs: []int64{targetID},
SyncGroup: 1,
}
case bridgev2.Kick:
task = &socket.RemoveParticipantTask{
ThreadID: threadID,
ContactID: targetID,
}
default:
return nil, nil
}
_, err := m.Client.ExecuteTasks(ctx, task)
if err != nil {
return nil, err
}
return &bridgev2.MatrixMembershipResult{}, nil
}
35 changes: 35 additions & 0 deletions pkg/connector/handlewhatsapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"maunium.net/go/mautrix/bridgev2/networkid"
"maunium.net/go/mautrix/bridgev2/simplevent"
"maunium.net/go/mautrix/bridgev2/status"
"maunium.net/go/mautrix/event"

"go.mau.fi/mautrix-meta/pkg/messagix/types"
"go.mau.fi/mautrix-meta/pkg/metaid"
Expand Down Expand Up @@ -133,6 +134,40 @@ func (m *MetaClient) e2eeEventHandler(rawEvt any) bool {
Message: evt.PermanentDisconnectDescription(),
}
m.UserLogin.BridgeState.Send(m.waState)
case *events.GroupInfo:
portalKey := m.makeWAPortalKey(evt.JID)
memberChanges := &bridgev2.ChatMemberList{
MemberMap: make(map[networkid.UserID]bridgev2.ChatMember),
}
for _, userID := range evt.Join {
memberChanges.MemberMap.Set(bridgev2.ChatMember{
EventSender: m.makeWAEventSender(userID),
Membership: event.MembershipJoin,
})
}
for _, userID := range evt.Leave {
memberChanges.MemberMap.Set(bridgev2.ChatMember{
EventSender: m.makeWAEventSender(userID),
Membership: event.MembershipLeave,
PrevMembership: event.MembershipJoin,
})
}
if len(memberChanges.MemberMap) > 0 {
eventMeta := simplevent.EventMeta{
Type: bridgev2.RemoteEventChatInfoChange,
PortalKey: portalKey,
Timestamp: evt.Timestamp,
}
if evt.Sender != nil {
eventMeta.Sender = m.makeWAEventSender(*evt.Sender)
}
m.UserLogin.QueueRemoteEvent(&simplevent.ChatInfoChange{
EventMeta: eventMeta,
ChatInfoChange: &bridgev2.ChatInfoChange{
MemberChanges: memberChanges,
},
})
}
default:
log.Debug().Type("event_type", rawEvt).Msg("Unhandled WhatsApp event")
}
Expand Down