Skip to content

Commit e0828ff

Browse files
committed
Add mautrix iMessage bridge
1 parent 12215c5 commit e0828ff

24 files changed

Lines changed: 2815 additions & 0 deletions

File tree

Package.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ var products: [Product] = [
3535
name: "IMessage",
3636
targets: ["IMessage"]
3737
),
38+
.library(
39+
name: "IMessageBridgeKit",
40+
type: .dynamic,
41+
targets: ["IMessageBridgeKit"]
42+
),
3843
.executable(name: "imessage-cli", targets: ["IMessageCLI"]),
3944
.executable(name: "IMDatabaseTestBench", targets: ["IMDatabaseTestBench"]),
4045
]
@@ -102,6 +107,15 @@ var targets: [Target] = [
102107
],
103108
path: "src/IMessage/Sources/IMessage"
104109
),
110+
.target(
111+
name: "IMessageBridgeKit",
112+
dependencies: [
113+
"IMessage",
114+
"IMessageCore",
115+
"PlatformSDK",
116+
],
117+
path: "src/IMessage/Sources/IMessageBridgeKit"
118+
),
105119
.target(
106120
name: "IMessagePrivateSPI",
107121
path: "src/IMessage/Sources/IMessagePrivateSPI",

bridge-readme.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# mautrix-imessage bridgev2
2+
3+
This repo includes a bridgev2 Matrix bridge entrypoint at `cmd/mautrix-imessage`.
4+
5+
The bridge is integrated with the Swift iMessage runtime through `IMessageBridgeKit`, a Swift dynamic library with a C ABI. It does not shell out to `imessage-cli`.
6+
7+
## Build
8+
9+
```sh
10+
swift build --product IMessageBridgeKit
11+
swift_bin="$(swift build --show-bin-path)"
12+
CGO_LDFLAGS="-L${swift_bin} -Wl,-rpath,${swift_bin}" \
13+
go build -tags nocrypto ./cmd/mautrix-imessage
14+
```
15+
16+
The `nocrypto` tag avoids linking mautrix's optional libolm dependency while still keeping cgo enabled for the Swift bridge library.
17+
18+
The bridge currently supports local-login, startup chat/message sync, live state-sync events, Matrix text/file sends, replies, edits, unsend, reactions, read receipts, and typing.
19+
20+
It must run on macOS with the usual platform-imessage permissions for Messages data and UI automation.

cmd/mautrix-imessage/main.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package main
2+
3+
import (
4+
"maunium.net/go/mautrix/bridgev2/matrix/mxmain"
5+
6+
"github.com/beeper/platform-imessage/pkg/connector"
7+
)
8+
9+
var (
10+
Tag = "unknown"
11+
Commit = "unknown"
12+
BuildTime = "unknown"
13+
)
14+
15+
var m = mxmain.BridgeMain{
16+
Name: "mautrix-imessage",
17+
URL: "https://github.com/beeper/platform-imessage",
18+
Description: "A Matrix-iMessage bridge using platform-imessage and mautrix bridgev2.",
19+
Version: "0.1.0",
20+
Connector: &connector.Connector{},
21+
}
22+
23+
func main() {
24+
m.InitVersion(Tag, Commit, BuildTime)
25+
m.Run()
26+
}

go.mod

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
module github.com/beeper/platform-imessage
2+
3+
go 1.25.0
4+
5+
toolchain go1.26.2
6+
7+
require (
8+
github.com/rs/zerolog v1.35.1
9+
go.mau.fi/util v0.9.9-0.20260511124621-9241e81bdf25
10+
maunium.net/go/mautrix v0.27.1-0.20260513120123-5fba7e3afae4
11+
)
12+
13+
require (
14+
filippo.io/edwards25519 v1.2.0 // indirect
15+
github.com/coder/websocket v1.8.14 // indirect
16+
github.com/coreos/go-systemd/v22 v22.7.0 // indirect
17+
github.com/lib/pq v1.12.3 // indirect
18+
github.com/mattn/go-colorable v0.1.14 // indirect
19+
github.com/mattn/go-isatty v0.0.20 // indirect
20+
github.com/mattn/go-sqlite3 v1.14.44 // indirect
21+
github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81 // indirect
22+
github.com/rs/xid v1.6.0 // indirect
23+
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
24+
github.com/tidwall/gjson v1.18.0 // indirect
25+
github.com/tidwall/match v1.1.1 // indirect
26+
github.com/tidwall/pretty v1.2.1 // indirect
27+
github.com/tidwall/sjson v1.2.5 // indirect
28+
github.com/yuin/goldmark v1.8.2 // indirect
29+
go.mau.fi/zeroconfig v0.2.0 // indirect
30+
golang.org/x/crypto v0.50.0 // indirect
31+
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect
32+
golang.org/x/net v0.53.0 // indirect
33+
golang.org/x/sync v0.20.0 // indirect
34+
golang.org/x/sys v0.43.0 // indirect
35+
golang.org/x/text v0.36.0 // indirect
36+
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
37+
gopkg.in/yaml.v3 v3.0.1 // indirect
38+
maunium.net/go/mauflag v1.0.0 // indirect
39+
)

go.sum

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
2+
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
3+
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
4+
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
5+
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
6+
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
7+
github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA=
8+
github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w=
9+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
10+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
11+
github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
12+
github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
13+
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
14+
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
15+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
16+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
17+
github.com/mattn/go-sqlite3 v1.14.44 h1:3VSe+xafpbzsLbdr2AWlAZk9yRHiBhTBakioXaCKTF8=
18+
github.com/mattn/go-sqlite3 v1.14.44/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ=
19+
github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81 h1:WDsQxOJDy0N1VRAjXLpi8sCEZRSGarLWQevDxpTBRrM=
20+
github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
21+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
22+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
23+
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
24+
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
25+
github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI=
26+
github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw=
27+
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
28+
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
29+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
30+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
31+
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
32+
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
33+
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
34+
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
35+
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
36+
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
37+
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
38+
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
39+
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
40+
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
41+
github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE=
42+
github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
43+
go.mau.fi/util v0.9.9-0.20260511124621-9241e81bdf25 h1:YPEmc+li7TF6C9AdRTcSLMb6yCHdF27/wNT7kFLIVNg=
44+
go.mau.fi/util v0.9.9-0.20260511124621-9241e81bdf25/go.mod h1:jE9FfhbgEgAwxei6lomO9v8zdCIATcquONUu4vjRwSs=
45+
go.mau.fi/zeroconfig v0.2.0 h1:e/OGEERqVRRKlgaro7E6bh8xXiKFSXB3eNNIud7FUjU=
46+
go.mau.fi/zeroconfig v0.2.0/go.mod h1:J0Vn0prHNOm493oZoQ84kq83ZaNCYZnq+noI1b1eN8w=
47+
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
48+
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
49+
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
50+
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
51+
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
52+
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
53+
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
54+
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
55+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
56+
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
57+
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
58+
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
59+
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
60+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
61+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
62+
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
63+
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
64+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
65+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
66+
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
67+
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
68+
maunium.net/go/mautrix v0.27.1-0.20260513120123-5fba7e3afae4 h1:zNC9eVAhw8FhKpM3AxNAh/iy75UEYX91uJUvqqAYlvo=
69+
maunium.net/go/mautrix v0.27.1-0.20260513120123-5fba7e3afae4/go.mod h1:3sOGhXi3P1V6/NruTA0gujkvTypXVUraWktCuTGyDuM=

pkg/connector/backfill.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package connector
2+
3+
import (
4+
"context"
5+
6+
"github.com/beeper/platform-imessage/pkg/imessage"
7+
"github.com/beeper/platform-imessage/pkg/imessageid"
8+
"maunium.net/go/mautrix/bridgev2"
9+
"maunium.net/go/mautrix/bridgev2/database"
10+
"maunium.net/go/mautrix/bridgev2/networkid"
11+
)
12+
13+
var _ bridgev2.BackfillingNetworkAPI = (*Client)(nil)
14+
15+
func (c *Client) FetchMessages(ctx context.Context, params bridgev2.FetchMessagesParams) (*bridgev2.FetchMessagesResponse, error) {
16+
threadID := string(params.Portal.ID)
17+
pagination := backfillPagination(params)
18+
page, err := c.IM.Messages(threadID, pagination)
19+
if err != nil {
20+
return nil, err
21+
}
22+
23+
messages := make([]*bridgev2.BackfillMessage, 0, len(page.Items))
24+
for i := len(page.Items) - 1; i >= 0; i-- {
25+
msg := page.Items[i]
26+
if msg.ThreadID == "" {
27+
msg.ThreadID = threadID
28+
}
29+
converted, err := c.convertMessageFromIMessage(ctx, params.Portal, c.Main.Bridge.Bot, msg)
30+
if err != nil {
31+
return nil, err
32+
}
33+
reactions := make([]*bridgev2.BackfillReaction, 0, len(msg.Reactions))
34+
for _, reaction := range msg.Reactions {
35+
reactions = append(reactions, &bridgev2.BackfillReaction{
36+
Sender: bridgev2.EventSender{Sender: imessageid.MakeUserID(reaction.ParticipantID)},
37+
EmojiID: networkid.EmojiID(reaction.ID),
38+
Emoji: reaction.ReactionKey,
39+
})
40+
}
41+
messages = append(messages, &bridgev2.BackfillMessage{
42+
ConvertedMessage: converted,
43+
Sender: c.sender(msg),
44+
ID: imessageid.MakeMessageID(msg.ID),
45+
TxnID: networkid.TransactionID(msg.ID),
46+
Timestamp: messageTimestamp(msg),
47+
StreamOrder: msg.Timestamp,
48+
Reactions: reactions,
49+
})
50+
}
51+
52+
return &bridgev2.FetchMessagesResponse{
53+
Messages: messages,
54+
Cursor: networkid.PaginationCursor(nextBackfillCursor(page, messages)),
55+
HasMore: page.HasMore,
56+
Forward: params.Forward,
57+
}, nil
58+
}
59+
60+
func backfillPagination(params bridgev2.FetchMessagesParams) *imessage.Pagination {
61+
cursor := string(params.Cursor)
62+
if cursor == "" {
63+
cursor = cursorFromMessage(params.AnchorMessage)
64+
}
65+
if cursor == "" {
66+
return nil
67+
}
68+
direction := "before"
69+
if params.Forward {
70+
direction = "after"
71+
}
72+
return &imessage.Pagination{
73+
Cursor: cursor,
74+
Direction: direction,
75+
}
76+
}
77+
78+
func cursorFromMessage(msg *database.Message) string {
79+
if msg == nil {
80+
return ""
81+
}
82+
if meta, ok := msg.Metadata.(*imessageid.MessageMetadata); ok && meta.Cursor != "" {
83+
return meta.Cursor
84+
}
85+
return string(msg.ID)
86+
}
87+
88+
func nextBackfillCursor(page *imessage.Page[imessage.Message], messages []*bridgev2.BackfillMessage) string {
89+
if page == nil {
90+
return ""
91+
}
92+
if page.OldestCursor != "" {
93+
return page.OldestCursor
94+
}
95+
if len(messages) == 0 {
96+
return ""
97+
}
98+
return string(messages[0].ID)
99+
}

pkg/connector/capabilities.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package connector
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
"go.mau.fi/util/jsontime"
8+
"go.mau.fi/util/ptr"
9+
"maunium.net/go/mautrix/bridgev2"
10+
"maunium.net/go/mautrix/event"
11+
)
12+
13+
const maxTextLength = 200_000
14+
const maxFileSize = 100 * 1024 * 1024
15+
16+
var generalCaps = &bridgev2.NetworkGeneralCapabilities{
17+
ImplicitReadReceipts: true,
18+
Provisioning: bridgev2.ProvisioningCapabilities{
19+
ResolveIdentifier: bridgev2.ResolveIdentifierCapabilities{
20+
CreateDM: true,
21+
AnyPhone: true,
22+
ContactList: true,
23+
Search: true,
24+
},
25+
},
26+
}
27+
28+
func (c *Connector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities {
29+
return generalCaps
30+
}
31+
32+
func (c *Connector) GetBridgeInfoVersion() (info, capabilities int) {
33+
return 1, 1
34+
}
35+
36+
var roomCaps = &event.RoomFeatures{
37+
ID: "com.beeper.imessage.capabilities.2026_06_04",
38+
Formatting: map[event.FormattingFeature]event.CapabilitySupportLevel{
39+
event.FmtBold: event.CapLevelDropped,
40+
event.FmtItalic: event.CapLevelDropped,
41+
event.FmtStrikethrough: event.CapLevelDropped,
42+
event.FmtInlineLink: event.CapLevelDropped,
43+
event.FmtUserLink: event.CapLevelDropped,
44+
},
45+
File: map[event.CapabilityMsgType]*event.FileFeatures{
46+
event.MsgImage: {
47+
MimeTypes: map[string]event.CapabilitySupportLevel{"*/*": event.CapLevelFullySupported},
48+
Caption: event.CapLevelDropped,
49+
MaxSize: maxFileSize,
50+
},
51+
event.MsgVideo: {
52+
MimeTypes: map[string]event.CapabilitySupportLevel{"*/*": event.CapLevelFullySupported},
53+
Caption: event.CapLevelDropped,
54+
MaxSize: maxFileSize,
55+
},
56+
event.MsgAudio: {
57+
MimeTypes: map[string]event.CapabilitySupportLevel{"*/*": event.CapLevelFullySupported},
58+
Caption: event.CapLevelDropped,
59+
MaxSize: maxFileSize,
60+
},
61+
event.MsgFile: {
62+
MimeTypes: map[string]event.CapabilitySupportLevel{"*/*": event.CapLevelFullySupported},
63+
Caption: event.CapLevelDropped,
64+
MaxSize: maxFileSize,
65+
},
66+
},
67+
MaxTextLength: maxTextLength,
68+
Reply: event.CapLevelFullySupported,
69+
Edit: event.CapLevelFullySupported,
70+
EditMaxAge: ptr.Ptr(jsontime.S(15 * time.Minute)),
71+
Delete: event.CapLevelFullySupported,
72+
DeleteForMe: false,
73+
DeleteMaxAge: ptr.Ptr(jsontime.S(2 * time.Minute)),
74+
Reaction: event.CapLevelFullySupported,
75+
ReactionCount: 1,
76+
ReadReceipts: true,
77+
TypingNotifications: true,
78+
MarkAsUnread: true,
79+
DeleteChat: true,
80+
}
81+
82+
func (c *Client) GetCapabilities(ctx context.Context, portal *bridgev2.Portal) *event.RoomFeatures {
83+
return roomCaps.Clone()
84+
}

0 commit comments

Comments
 (0)