Skip to main content

ruma_events/
enums.rs

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