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