Skip to main content

ruma_events/
enums.rs

1use ruma_common::{
2    EventId, MilliSecondsSinceUnixEpoch, OwnedRoomId, RoomId, TransactionId, UserId,
3    serde::{JsonCastable, from_raw_json_value},
4};
5#[cfg(feature = "unstable-msc3381")]
6use ruma_events::{
7    poll::{start::PollStartEventContent, unstable_start::UnstablePollStartEventContent},
8    room::encrypted::Replacement,
9};
10use ruma_macros::{EventEnumFromEvent, event_enum};
11use serde::{Deserialize, Serialize, de};
12use serde_json::value::RawValue as RawJsonValue;
13
14use super::room::encrypted;
15
16/// Event types that servers should send as [stripped state] to help clients identify a room when
17/// they can't access the full room state.
18///
19/// [stripped state]: https://spec.matrix.org/v1.19/client-server-api/#stripped-state
20pub const RECOMMENDED_STRIPPED_STATE_EVENT_TYPES: &[StateEventType] = &[
21    StateEventType::RoomCreate,
22    StateEventType::RoomName,
23    StateEventType::RoomAvatar,
24    StateEventType::RoomTopic,
25    StateEventType::RoomJoinRules,
26    StateEventType::RoomCanonicalAlias,
27    StateEventType::RoomEncryption,
28];
29
30/// Event types that servers should transfer upon [room upgrade]. The exact details for what is
31/// transferred is left as an implementation detail.
32///
33/// [room upgrade]: https://spec.matrix.org/v1.19/client-server-api/#server-behaviour-21
34pub const RECOMMENDED_TRANSFERABLE_STATE_EVENT_TYPES: &[StateEventType] = &[
35    StateEventType::RoomServerAcl,
36    StateEventType::RoomEncryption,
37    StateEventType::RoomName,
38    StateEventType::RoomAvatar,
39    StateEventType::RoomTopic,
40    StateEventType::RoomGuestAccess,
41    StateEventType::RoomHistoryVisibility,
42    StateEventType::RoomJoinRules,
43    StateEventType::RoomPowerLevels,
44    #[cfg(feature = "unstable-msc4495")]
45    StateEventType::RoomPresenceSharing,
46];
47
48/// Event types that may be requested using the stripped state endpoint. ([MSC4560])
49///
50/// [MSC4560]: https://github.com/matrix-org/matrix-spec-proposals/pull/4560
51#[cfg(feature = "unstable-msc4560")]
52pub const ALLOWED_STRIPPED_STATE_EVENTS: &[StateEventType] = &[
53    StateEventType::RoomCreate,
54    StateEventType::RoomName,
55    StateEventType::RoomAvatar,
56    StateEventType::RoomTopic,
57    StateEventType::RoomJoinRules,
58    StateEventType::RoomCanonicalAlias,
59    StateEventType::RoomGuestAccess,
60    StateEventType::RoomHistoryVisibility,
61    StateEventType::RoomEncryption,
62    StateEventType::SpaceChild,
63    StateEventType::SpaceParent,
64];
65
66event_enum! {
67    /// Any global account data event.
68    enum GlobalAccountData {
69        "m.direct" => super::direct,
70        #[cfg(feature = "unstable-msc4359")]
71        #[ruma_enum(ident = DoNotDisturb, alias = "m.do_not_disturb")]
72        "dm.filament.do_not_disturb" => super::do_not_disturb,
73        "m.identity_server" => super::identity_server,
74        "m.invite_permission_config" => super::invite_permission_config,
75        #[cfg(feature = "unstable-msc4380")]
76        #[ruma_enum(ident = UnstableInvitePermissionConfig)]
77        "org.matrix.msc4380.invite_permission_config" => super::invite_permission_config,
78        "m.ignored_user_list" => super::ignored_user_list,
79        "m.image_pack.rooms" => super::image_pack::rooms,
80        "m.push_rules" => super::push_rules,
81        "m.secret_storage.default_key" => super::secret_storage::default_key,
82        "m.secret_storage.key.*" => super::secret_storage::key,
83        #[cfg(feature = "unstable-msc4278")]
84        "m.media_preview_config" => super::media_preview_config,
85        #[cfg(feature = "unstable-msc4278")]
86        #[ruma_enum(ident = UnstableMediaPreviewConfig)]
87        "io.element.msc4278.media_preview_config" => super::media_preview_config,
88        "m.recent_emoji" => super::recent_emoji,
89        "m.key_backup" => super::key_backup,
90        #[cfg(feature = "unstable-msc4495")]
91        #[ruma_enum(ident = PresenceSharing)]
92        "org.continuwuity.presence_v2.msc4495.presence.sharing" => super::presence::sharing,
93        #[cfg(feature = "unstable-msc4495")]
94        #[ruma_enum(ident = PresencePrompted)]
95        "org.continuwuity.presence_v2.msc4495.presence.prompted" => super::presence::prompted,
96        #[cfg(feature = "unstable-msc4532")]
97        #[ruma_enum(ident = PresencePersistent)]
98        "org.continuwuity.presence_v2.msc4532.presence.persistent" => super::presence::persistent,
99    }
100
101    /// Any room account data event.
102    enum RoomAccountData {
103        "m.fully_read" => super::fully_read,
104        "m.tag" => super::tag,
105        "m.marked_unread" => super::marked_unread,
106        #[cfg(feature = "unstable-msc2867")]
107        #[ruma_enum(ident = UnstableMarkedUnread)]
108        "com.famedly.marked_unread" => super::marked_unread,
109        #[cfg(feature = "unstable-msc4278")]
110        "m.media_preview_config" => super::media_preview_config,
111        #[cfg(feature = "unstable-msc4278")]
112        #[ruma_enum(ident = UnstableMediaPreviewConfig)]
113        "io.element.msc4278.media_preview_config" => super::media_preview_config,
114        #[cfg(feature = "unstable-msc3230")]
115        #[ruma_enum(alias = "m.space_order")]
116        "org.matrix.msc3230.space_order" => super::space_order,
117    }
118
119    /// Any ephemeral room event.
120    enum EphemeralRoom {
121        "m.receipt" => super::receipt,
122        "m.typing" => super::typing,
123    }
124
125    /// Any message-like event.
126    enum MessageLike {
127        #[cfg(feature = "unstable-msc3927")]
128        #[ruma_enum(alias = "m.audio")]
129        "org.matrix.msc1767.audio" => super::audio,
130        "m.call.answer" => super::call::answer,
131        "m.call.invite" => super::call::invite,
132        "m.call.hangup" => super::call::hangup,
133        "m.call.candidates" => super::call::candidates,
134        "m.call.negotiate" => super::call::negotiate,
135        "m.call.reject" => super::call::reject,
136        #[ruma_enum(alias = "org.matrix.call.sdp_stream_metadata_changed")]
137        "m.call.sdp_stream_metadata_changed" => super::call::sdp_stream_metadata_changed,
138        "m.call.select_answer" => super::call::select_answer,
139        #[cfg(feature = "unstable-msc3954")]
140        #[ruma_enum(alias = "m.emote")]
141        "org.matrix.msc1767.emote" => super::emote,
142        #[cfg(feature = "unstable-msc3956")]
143        #[ruma_enum(alias = "m.encrypted")]
144        "org.matrix.msc1767.encrypted" => super::encrypted,
145        #[cfg(feature = "unstable-msc3551")]
146        #[ruma_enum(alias = "m.file")]
147        "org.matrix.msc1767.file" => super::file,
148        #[cfg(feature = "unstable-msc3552")]
149        #[ruma_enum(alias = "m.image")]
150        "org.matrix.msc1767.image" => super::image,
151        "m.key.verification.ready" => super::key::verification::ready,
152        "m.key.verification.start" => super::key::verification::start,
153        "m.key.verification.cancel" => super::key::verification::cancel,
154        "m.key.verification.accept" => super::key::verification::accept,
155        "m.key.verification.key" => super::key::verification::key,
156        "m.key.verification.mac" => super::key::verification::mac,
157        "m.key.verification.done" => super::key::verification::done,
158        #[cfg(feature = "unstable-msc3488")]
159        "m.location" => super::location,
160        #[cfg(feature = "unstable-msc1767")]
161        #[ruma_enum(alias = "m.message")]
162        "org.matrix.msc1767.message" => super::message,
163        #[cfg(feature = "unstable-msc3381")]
164        "m.poll.start" => super::poll::start,
165        #[cfg(feature = "unstable-msc3381")]
166        #[ruma_enum(ident = UnstablePollStart)]
167        "org.matrix.msc3381.poll.start" => super::poll::unstable_start,
168        #[cfg(feature = "unstable-msc3381")]
169        "m.poll.response" => super::poll::response,
170        #[cfg(feature = "unstable-msc3381")]
171        #[ruma_enum(ident = UnstablePollResponse)]
172        "org.matrix.msc3381.poll.response" => super::poll::unstable_response,
173        #[cfg(feature = "unstable-msc3381")]
174        "m.poll.end" => super::poll::end,
175        #[cfg(feature = "unstable-msc3381")]
176        #[ruma_enum(ident = UnstablePollEnd)]
177        "org.matrix.msc3381.poll.end" => super::poll::unstable_end,
178        #[cfg(feature = "unstable-msc3489")]
179        #[ruma_enum(alias = "m.beacon")]
180        "org.matrix.msc3672.beacon" => super::beacon,
181        "m.reaction" => super::reaction,
182        "m.room.encrypted" => super::room::encrypted,
183        "m.room.message" => super::room::message,
184        "m.room.redaction" => super::room::redaction,
185        "m.sticker" => super::sticker,
186        #[cfg(feature = "unstable-msc3553")]
187        #[ruma_enum(alias = "m.video")]
188        "org.matrix.msc1767.video" => super::video,
189        #[cfg(feature = "unstable-msc3245")]
190        #[ruma_enum(alias = "m.voice")]
191        "org.matrix.msc3245.voice.v2" => super::voice,
192        #[cfg(feature = "unstable-msc4075")]
193        #[ruma_enum(alias = "m.call.notify")]
194        #[allow(deprecated)]
195        "org.matrix.msc4075.call.notify" => super::call::notify,
196        #[cfg(feature = "unstable-msc4075")]
197        #[ruma_enum(alias = "m.rtc.notification")]
198        "org.matrix.msc4075.rtc.notification" => super::rtc::notification,
199        #[cfg(feature = "unstable-msc4310")]
200        #[ruma_enum(alias = "m.rtc.decline")]
201        "org.matrix.msc4310.rtc.decline" => super::rtc::decline,
202    }
203
204    /// Any state event.
205    enum State {
206        "m.policy.rule.room" => super::policy::rule::room,
207        "m.policy.rule.server" => super::policy::rule::server,
208        "m.policy.rule.user" => super::policy::rule::user,
209        "m.room.avatar" => super::room::avatar,
210        "m.room.canonical_alias" => super::room::canonical_alias,
211        "m.room.create" => super::room::create,
212        "m.room.encryption" => super::room::encryption,
213        #[cfg(feature = "unstable-msc4362")]
214        "m.room.encrypted" => super::room::encrypted::unstable_state,
215        "m.room.guest_access" => super::room::guest_access,
216        "m.room.history_visibility" => super::room::history_visibility,
217        "m.room.image_pack" => super::room::image_pack,
218        "m.room.join_rules" => super::room::join_rules,
219        #[cfg(feature = "unstable-msc4334")]
220        #[ruma_enum(alias = "m.room.language")]
221        "org.matrix.msc4334.room.language" => super::room::language,
222        "m.room.member" => super::room::member,
223        "m.room.name" => super::room::name,
224        "m.room.pinned_events" => super::room::pinned_events,
225        "m.room.policy" => super::room::policy,
226        "m.room.power_levels" => super::room::power_levels,
227        #[cfg(feature = "unstable-msc1763")]
228        #[ruma_enum(alias = "m.room.retention")]
229        "org.matrix.msc1763.retention" => super::room::retention,
230        "m.room.server_acl" => super::room::server_acl,
231        "m.room.third_party_invite" => super::room::third_party_invite,
232        "m.room.tombstone" => super::room::tombstone,
233        "m.room.topic" => super::room::topic,
234        #[cfg(feature = "unstable-msc4495")]
235        #[ruma_enum(alias = "m.room.presence_sharing")]
236        "org.continuwuity.presence_v2.msc4495.room.presence_sharing" => super::room::presence_sharing,
237        "m.space.child" => super::space::child,
238        "m.space.parent" => super::space::parent,
239        #[cfg(feature = "unstable-msc3489")]
240        #[ruma_enum(alias = "m.beacon_info")]
241        "org.matrix.msc3672.beacon_info" => super::beacon_info,
242        #[cfg(feature = "unstable-msc3401")]
243        #[ruma_enum(alias = "m.call.member")]
244        "org.matrix.msc3401.call.member" => super::call::member,
245        #[cfg(feature = "unstable-msc4171")]
246        #[ruma_enum(alias = "m.member_hints")]
247        "io.element.functional_members" => super::member_hints,
248    }
249
250    /// Any to-device event.
251    enum ToDevice {
252        "m.dummy" => super::dummy,
253        "m.room_key" => super::room_key,
254        "m.room_key_bundle" => super::room_key_bundle,
255        "m.room_key_request" => super::room_key_request,
256        "m.room_key.withheld" => super::room_key::withheld,
257        "m.forwarded_room_key" => super::forwarded_room_key,
258        "m.key.verification.request" => super::key::verification::request,
259        "m.key.verification.ready" => super::key::verification::ready,
260        "m.key.verification.start" => super::key::verification::start,
261        "m.key.verification.cancel" => super::key::verification::cancel,
262        "m.key.verification.accept" => super::key::verification::accept,
263        "m.key.verification.key" => super::key::verification::key,
264        "m.key.verification.mac" => super::key::verification::mac,
265        "m.key.verification.done" => super::key::verification::done,
266        "m.room.encrypted" => super::room::encrypted,
267        "m.secret.request"=> super::secret::request,
268        "m.secret.send" => super::secret::send,
269        #[cfg(feature = "unstable-msc4385")]
270        #[ruma_enum(alias = "m.secret.push")]
271        "io.element.msc4385.secret.push" => super::secret::push,
272        #[cfg(feature = "unstable-msc4471")]
273        #[ruma_enum(alias = "m.stream.subscribe")]
274        "org.matrix.msc4471.stream.subscribe" => super::stream::subscribe,
275        #[cfg(feature = "unstable-msc4471")]
276        #[ruma_enum(alias = "m.stream.cancel")]
277        "org.matrix.msc4471.stream.cancel" => super::stream::cancel,
278        #[cfg(feature = "unstable-msc4471")]
279        #[ruma_enum(alias = "m.stream.update")]
280        "org.matrix.msc4471.stream.update" => super::stream::update,
281    }
282}
283
284macro_rules! timeline_event_accessors {
285    (
286        $(
287            #[doc = $docs:literal]
288            pub fn $field:ident(&self) -> $ty:ty;
289        )*
290    ) => {
291        $(
292            #[doc = $docs]
293            pub fn $field(&self) -> $ty {
294                match self {
295                    Self::MessageLike(ev) => ev.$field(),
296                    Self::State(ev) => ev.$field(),
297                }
298            }
299        )*
300    };
301}
302
303/// Any room event.
304#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
305#[derive(Clone, Debug, EventEnumFromEvent)]
306pub enum AnyTimelineEvent {
307    /// Any message-like event.
308    MessageLike(AnyMessageLikeEvent),
309
310    /// Any state event.
311    State(AnyStateEvent),
312}
313
314impl AnyTimelineEvent {
315    timeline_event_accessors! {
316        /// Returns this event's `origin_server_ts` field.
317        pub fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch;
318
319        /// Returns this event's `room_id` field.
320        pub fn room_id(&self) -> &RoomId;
321
322        /// Returns this event's `event_id` field.
323        pub fn event_id(&self) -> &EventId;
324
325        /// Returns this event's `sender` field.
326        pub fn sender(&self) -> &UserId;
327
328        /// Returns this event's `transaction_id` from inside `unsigned`, if there is one.
329        pub fn transaction_id(&self) -> Option<&TransactionId>;
330
331        /// Returns whether this event is in its redacted form or not.
332        pub fn is_redacted(&self) -> bool;
333    }
334
335    /// Returns this event's `type`.
336    pub fn event_type(&self) -> TimelineEventType {
337        match self {
338            Self::MessageLike(e) => e.event_type().into(),
339            Self::State(e) => e.event_type().into(),
340        }
341    }
342}
343
344/// Any sync room event.
345///
346/// Sync room events are room event without a `room_id`, as returned in `/sync` responses.
347#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
348#[derive(Clone, Debug, EventEnumFromEvent)]
349pub enum AnySyncTimelineEvent {
350    /// Any sync message-like event.
351    MessageLike(AnySyncMessageLikeEvent),
352
353    /// Any sync state event.
354    State(AnySyncStateEvent),
355}
356
357impl AnySyncTimelineEvent {
358    timeline_event_accessors! {
359        /// Returns this event's `origin_server_ts` field.
360        pub fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch;
361
362        /// Returns this event's `event_id` field.
363        pub fn event_id(&self) -> &EventId;
364
365        /// Returns this event's `sender` field.
366        pub fn sender(&self) -> &UserId;
367
368        /// Returns this event's `transaction_id` from inside `unsigned`, if there is one.
369        pub fn transaction_id(&self) -> Option<&TransactionId>;
370
371        /// Returns whether this event is in its redacted form or not.
372        pub fn is_redacted(&self) -> bool;
373    }
374
375    /// Returns this event's `type`.
376    pub fn event_type(&self) -> TimelineEventType {
377        match self {
378            Self::MessageLike(e) => e.event_type().into(),
379            Self::State(e) => e.event_type().into(),
380        }
381    }
382
383    /// Converts `self` to an `AnyTimelineEvent` by adding the given a room ID.
384    pub fn into_full_event(self, room_id: OwnedRoomId) -> AnyTimelineEvent {
385        match self {
386            Self::MessageLike(ev) => AnyTimelineEvent::MessageLike(ev.into_full_event(room_id)),
387            Self::State(ev) => AnyTimelineEvent::State(ev.into_full_event(room_id)),
388        }
389    }
390}
391
392impl From<AnyTimelineEvent> for AnySyncTimelineEvent {
393    fn from(ev: AnyTimelineEvent) -> Self {
394        match ev {
395            AnyTimelineEvent::MessageLike(ev) => Self::MessageLike(ev.into()),
396            AnyTimelineEvent::State(ev) => Self::State(ev.into()),
397        }
398    }
399}
400
401/// Any room event content.
402#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
403#[derive(Clone, Debug, EventEnumFromEvent, Serialize)]
404#[serde(untagged)]
405pub enum AnyTimelineEventContent {
406    /// Any message-like event content.
407    MessageLike(AnyMessageLikeEventContent),
408
409    /// Any state event content.
410    State(AnyStateEventContent),
411}
412
413impl AnyTimelineEventContent {
414    /// Get the event's type
415    pub fn event_type(&self) -> TimelineEventType {
416        match self {
417            Self::MessageLike(content) => {
418                <AnyMessageLikeEventContent as crate::MessageLikeEventContent>::event_type(content)
419                    .into()
420            }
421            Self::State(content) => {
422                <AnyStateEventContent as crate::StateEventContent>::event_type(content).into()
423            }
424        }
425    }
426}
427
428impl JsonCastable<AnyTimelineEventContent> for AnyMessageLikeEventContent {}
429impl JsonCastable<AnyTimelineEventContent> for AnyStateEventContent {}
430
431#[derive(Deserialize)]
432#[allow(clippy::exhaustive_structs)]
433struct EventDeHelper {
434    state_key: Option<de::IgnoredAny>,
435}
436
437impl<'de> Deserialize<'de> for AnyTimelineEvent {
438    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
439    where
440        D: de::Deserializer<'de>,
441    {
442        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
443        let EventDeHelper { state_key } = from_raw_json_value(&json)?;
444
445        if state_key.is_some() {
446            Ok(AnyTimelineEvent::State(from_raw_json_value(&json)?))
447        } else {
448            Ok(AnyTimelineEvent::MessageLike(from_raw_json_value(&json)?))
449        }
450    }
451}
452
453impl<'de> Deserialize<'de> for AnySyncTimelineEvent {
454    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
455    where
456        D: de::Deserializer<'de>,
457    {
458        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
459        let EventDeHelper { state_key } = from_raw_json_value(&json)?;
460
461        if state_key.is_some() {
462            Ok(AnySyncTimelineEvent::State(from_raw_json_value(&json)?))
463        } else {
464            Ok(AnySyncTimelineEvent::MessageLike(from_raw_json_value(&json)?))
465        }
466    }
467}
468
469impl AnyMessageLikeEventContent {
470    /// Get a copy of the event's `m.relates_to` field, if any.
471    ///
472    /// This is a helper function intended for encryption. There should not be a reason to access
473    /// `m.relates_to` without first destructuring an `AnyMessageLikeEventContent` otherwise.
474    pub fn relation(&self) -> Option<encrypted::Relation> {
475        #[cfg(feature = "unstable-msc3489")]
476        use super::beacon::BeaconEventContent;
477        use super::key::verification::{
478            accept::KeyVerificationAcceptEventContent, cancel::KeyVerificationCancelEventContent,
479            done::KeyVerificationDoneEventContent, key::KeyVerificationKeyEventContent,
480            mac::KeyVerificationMacEventContent, ready::KeyVerificationReadyEventContent,
481            start::KeyVerificationStartEventContent,
482        };
483        #[cfg(feature = "unstable-msc3381")]
484        use super::poll::{
485            end::PollEndEventContent, response::PollResponseEventContent,
486            unstable_end::UnstablePollEndEventContent,
487            unstable_response::UnstablePollResponseEventContent,
488        };
489
490        match self {
491            #[rustfmt::skip]
492            Self::KeyVerificationReady(KeyVerificationReadyEventContent { relates_to, .. })
493            | Self::KeyVerificationStart(KeyVerificationStartEventContent { relates_to, .. })
494            | Self::KeyVerificationCancel(KeyVerificationCancelEventContent { relates_to, .. })
495            | Self::KeyVerificationAccept(KeyVerificationAcceptEventContent { relates_to, .. })
496            | Self::KeyVerificationKey(KeyVerificationKeyEventContent { relates_to, .. })
497            | Self::KeyVerificationMac(KeyVerificationMacEventContent { relates_to, .. })
498            | Self::KeyVerificationDone(KeyVerificationDoneEventContent { relates_to, .. }) => {
499                Some(encrypted::Relation::Reference(relates_to.clone()))
500            },
501            Self::Reaction(ev) => Some(encrypted::Relation::Annotation(ev.relates_to.clone())),
502            Self::RoomEncrypted(ev) => ev.relates_to.clone(),
503            Self::RoomMessage(ev) => ev.relates_to.clone().map(Into::into),
504            #[cfg(feature = "unstable-msc1767")]
505            Self::Message(ev) => ev.relates_to.clone().map(Into::into),
506            #[cfg(feature = "unstable-msc3954")]
507            Self::Emote(ev) => ev.relates_to.clone().map(Into::into),
508            #[cfg(feature = "unstable-msc3956")]
509            Self::Encrypted(ev) => ev.relates_to.clone(),
510            #[cfg(feature = "unstable-msc3245")]
511            Self::Voice(ev) => ev.relates_to.clone().map(Into::into),
512            #[cfg(feature = "unstable-msc3927")]
513            Self::Audio(ev) => ev.relates_to.clone().map(Into::into),
514            #[cfg(feature = "unstable-msc3488")]
515            Self::Location(ev) => ev.relates_to.clone().map(Into::into),
516            #[cfg(feature = "unstable-msc3551")]
517            Self::File(ev) => ev.relates_to.clone().map(Into::into),
518            #[cfg(feature = "unstable-msc3552")]
519            Self::Image(ev) => ev.relates_to.clone().map(Into::into),
520            #[cfg(feature = "unstable-msc3553")]
521            Self::Video(ev) => ev.relates_to.clone().map(Into::into),
522            #[cfg(feature = "unstable-msc3381")]
523            Self::PollResponse(PollResponseEventContent { relates_to, .. })
524            | Self::UnstablePollResponse(UnstablePollResponseEventContent { relates_to, .. })
525            | Self::PollEnd(PollEndEventContent { relates_to, .. })
526            | Self::UnstablePollEnd(UnstablePollEndEventContent { relates_to, .. }) => {
527                Some(encrypted::Relation::Reference(relates_to.clone()))
528            }
529            #[cfg(feature = "unstable-msc3489")]
530            Self::Beacon(BeaconEventContent { relates_to, .. }) => {
531                Some(encrypted::Relation::Reference(relates_to.clone()))
532            }
533            #[cfg(feature = "unstable-msc3381")]
534            Self::UnstablePollStart(UnstablePollStartEventContent::New(content)) => {
535                content.relates_to.clone().map(Into::into)
536            }
537            #[cfg(feature = "unstable-msc3381")]
538            Self::UnstablePollStart(UnstablePollStartEventContent::Replacement(content)) => {
539                Some(encrypted::Relation::Replacement(Replacement::new(
540                    content.relates_to.event_id.clone(),
541                )))
542            }
543            #[cfg(feature = "unstable-msc3381")]
544            Self::PollStart(PollStartEventContent { relates_to, .. }) => {
545                relates_to.clone().map(Into::into)
546            }
547            #[cfg(feature = "unstable-msc4075")]
548            Self::CallNotify(_) => None,
549            #[cfg(feature = "unstable-msc4075")]
550            Self::RtcNotification(ev) => ev.relates_to.clone().map(encrypted::Relation::Reference),
551            #[cfg(feature = "unstable-msc4310")]
552            Self::RtcDecline(ev) => Some(encrypted::Relation::Reference(ev.relates_to.clone())),
553            Self::CallSdpStreamMetadataChanged(_)
554            | Self::CallNegotiate(_)
555            | Self::CallReject(_)
556            | Self::CallSelectAnswer(_)
557            | Self::CallAnswer(_)
558            | Self::CallInvite(_)
559            | Self::CallHangup(_)
560            | Self::CallCandidates(_)
561            | Self::RoomRedaction(_)
562            | Self::Sticker(_)
563            | Self::_Custom { .. } => None,
564        }
565    }
566}