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