ruma_events/
enums.rs

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