ruma_events/
enums.rs

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