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