1use ruma_common::{
2 EventId, MilliSecondsSinceUnixEpoch, OwnedRoomId, RoomId, TransactionId, UserId,
3 serde::{JsonCastable, 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, Serialize, de};
12use serde_json::value::RawValue as RawJsonValue;
13
14use super::room::encrypted;
15
16pub 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
30pub const RECOMMENDED_TRANSFERABLE_STATE_EVENT_TYPES: &[StateEventType] = &[
35 StateEventType::RoomServerAcl,
36 StateEventType::RoomEncryption,
37 StateEventType::RoomName,
38 StateEventType::RoomAvatar,
39 StateEventType::RoomTopic,
40 StateEventType::RoomGuestAccess,
41 StateEventType::RoomHistoryVisibility,
42 StateEventType::RoomJoinRules,
43 StateEventType::RoomPowerLevels,
44];
45
46event_enum! {
47 enum GlobalAccountData {
49 "m.direct" => super::direct,
50 #[cfg(feature = "unstable-msc4359")]
51 #[ruma_enum(ident = DoNotDisturb, alias = "m.do_not_disturb")]
52 "dm.filament.do_not_disturb" => super::do_not_disturb,
53 "m.identity_server" => super::identity_server,
54 "m.invite_permission_config" => super::invite_permission_config,
55 #[cfg(feature = "unstable-msc4380")]
56 #[ruma_enum(ident = UnstableInvitePermissionConfig)]
57 "org.matrix.msc4380.invite_permission_config" => super::invite_permission_config,
58 "m.ignored_user_list" => super::ignored_user_list,
59 "m.image_pack.rooms" => super::image_pack::rooms,
60 "m.push_rules" => super::push_rules,
61 "m.secret_storage.default_key" => super::secret_storage::default_key,
62 "m.secret_storage.key.*" => super::secret_storage::key,
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 "m.recent_emoji" => super::recent_emoji,
69 "m.key_backup" => super::key_backup,
70 }
71
72 enum RoomAccountData {
74 "m.fully_read" => super::fully_read,
75 "m.tag" => super::tag,
76 "m.marked_unread" => super::marked_unread,
77 #[cfg(feature = "unstable-msc2867")]
78 #[ruma_enum(ident = UnstableMarkedUnread)]
79 "com.famedly.marked_unread" => super::marked_unread,
80 #[cfg(feature = "unstable-msc4278")]
81 "m.media_preview_config" => super::media_preview_config,
82 #[cfg(feature = "unstable-msc4278")]
83 #[ruma_enum(ident = UnstableMediaPreviewConfig)]
84 "io.element.msc4278.media_preview_config" => super::media_preview_config,
85 #[cfg(feature = "unstable-msc3230")]
86 #[ruma_enum(alias = "m.space_order")]
87 "org.matrix.msc3230.space_order" => super::space_order,
88 }
89
90 enum EphemeralRoom {
92 "m.receipt" => super::receipt,
93 "m.typing" => super::typing,
94 }
95
96 enum MessageLike {
98 #[cfg(feature = "unstable-msc3927")]
99 #[ruma_enum(alias = "m.audio")]
100 "org.matrix.msc1767.audio" => super::audio,
101 "m.call.answer" => super::call::answer,
102 "m.call.invite" => super::call::invite,
103 "m.call.hangup" => super::call::hangup,
104 "m.call.candidates" => super::call::candidates,
105 "m.call.negotiate" => super::call::negotiate,
106 "m.call.reject" => super::call::reject,
107 #[ruma_enum(alias = "org.matrix.call.sdp_stream_metadata_changed")]
108 "m.call.sdp_stream_metadata_changed" => super::call::sdp_stream_metadata_changed,
109 "m.call.select_answer" => super::call::select_answer,
110 #[cfg(feature = "unstable-msc3954")]
111 #[ruma_enum(alias = "m.emote")]
112 "org.matrix.msc1767.emote" => super::emote,
113 #[cfg(feature = "unstable-msc3956")]
114 #[ruma_enum(alias = "m.encrypted")]
115 "org.matrix.msc1767.encrypted" => super::encrypted,
116 #[cfg(feature = "unstable-msc3551")]
117 #[ruma_enum(alias = "m.file")]
118 "org.matrix.msc1767.file" => super::file,
119 #[cfg(feature = "unstable-msc3552")]
120 #[ruma_enum(alias = "m.image")]
121 "org.matrix.msc1767.image" => super::image,
122 "m.key.verification.ready" => super::key::verification::ready,
123 "m.key.verification.start" => super::key::verification::start,
124 "m.key.verification.cancel" => super::key::verification::cancel,
125 "m.key.verification.accept" => super::key::verification::accept,
126 "m.key.verification.key" => super::key::verification::key,
127 "m.key.verification.mac" => super::key::verification::mac,
128 "m.key.verification.done" => super::key::verification::done,
129 #[cfg(feature = "unstable-msc3488")]
130 "m.location" => super::location,
131 #[cfg(feature = "unstable-msc1767")]
132 #[ruma_enum(alias = "m.message")]
133 "org.matrix.msc1767.message" => super::message,
134 #[cfg(feature = "unstable-msc3381")]
135 "m.poll.start" => super::poll::start,
136 #[cfg(feature = "unstable-msc3381")]
137 #[ruma_enum(ident = UnstablePollStart)]
138 "org.matrix.msc3381.poll.start" => super::poll::unstable_start,
139 #[cfg(feature = "unstable-msc3381")]
140 "m.poll.response" => super::poll::response,
141 #[cfg(feature = "unstable-msc3381")]
142 #[ruma_enum(ident = UnstablePollResponse)]
143 "org.matrix.msc3381.poll.response" => super::poll::unstable_response,
144 #[cfg(feature = "unstable-msc3381")]
145 "m.poll.end" => super::poll::end,
146 #[cfg(feature = "unstable-msc3381")]
147 #[ruma_enum(ident = UnstablePollEnd)]
148 "org.matrix.msc3381.poll.end" => super::poll::unstable_end,
149 #[cfg(feature = "unstable-msc3489")]
150 #[ruma_enum(alias = "m.beacon")]
151 "org.matrix.msc3672.beacon" => super::beacon,
152 "m.reaction" => super::reaction,
153 "m.room.encrypted" => super::room::encrypted,
154 "m.room.message" => super::room::message,
155 "m.room.redaction" => super::room::redaction,
156 "m.sticker" => super::sticker,
157 #[cfg(feature = "unstable-msc3553")]
158 #[ruma_enum(alias = "m.video")]
159 "org.matrix.msc1767.video" => super::video,
160 #[cfg(feature = "unstable-msc3245")]
161 #[ruma_enum(alias = "m.voice")]
162 "org.matrix.msc3245.voice.v2" => super::voice,
163 #[cfg(feature = "unstable-msc4075")]
164 #[ruma_enum(alias = "m.call.notify")]
165 #[allow(deprecated)]
166 "org.matrix.msc4075.call.notify" => super::call::notify,
167 #[cfg(feature = "unstable-msc4075")]
168 #[ruma_enum(alias = "m.rtc.notification")]
169 "org.matrix.msc4075.rtc.notification" => super::rtc::notification,
170 #[cfg(feature = "unstable-msc4310")]
171 #[ruma_enum(alias = "m.rtc.decline")]
172 "org.matrix.msc4310.rtc.decline" => super::rtc::decline,
173 }
174
175 enum State {
177 "m.policy.rule.room" => super::policy::rule::room,
178 "m.policy.rule.server" => super::policy::rule::server,
179 "m.policy.rule.user" => super::policy::rule::user,
180 "m.room.avatar" => super::room::avatar,
181 "m.room.canonical_alias" => super::room::canonical_alias,
182 "m.room.create" => super::room::create,
183 "m.room.encryption" => super::room::encryption,
184 #[cfg(feature = "unstable-msc4362")]
185 "m.room.encrypted" => super::room::encrypted::unstable_state,
186 "m.room.guest_access" => super::room::guest_access,
187 "m.room.history_visibility" => super::room::history_visibility,
188 "m.room.image_pack" => super::room::image_pack,
189 "m.room.join_rules" => super::room::join_rules,
190 #[cfg(feature = "unstable-msc4334")]
191 #[ruma_enum(alias = "m.room.language")]
192 "org.matrix.msc4334.room.language" => super::room::language,
193 "m.room.member" => super::room::member,
194 "m.room.name" => super::room::name,
195 "m.room.pinned_events" => super::room::pinned_events,
196 "m.room.policy" => super::room::policy,
197 "m.room.power_levels" => super::room::power_levels,
198 "m.room.server_acl" => super::room::server_acl,
199 "m.room.third_party_invite" => super::room::third_party_invite,
200 "m.room.tombstone" => super::room::tombstone,
201 "m.room.topic" => super::room::topic,
202 "m.space.child" => super::space::child,
203 "m.space.parent" => super::space::parent,
204 #[cfg(feature = "unstable-msc3489")]
205 #[ruma_enum(alias = "m.beacon_info")]
206 "org.matrix.msc3672.beacon_info" => super::beacon_info,
207 #[cfg(feature = "unstable-msc3401")]
208 #[ruma_enum(alias = "m.call.member")]
209 "org.matrix.msc3401.call.member" => super::call::member,
210 #[cfg(feature = "unstable-msc4171")]
211 #[ruma_enum(alias = "m.member_hints")]
212 "io.element.functional_members" => super::member_hints,
213 }
214
215 enum ToDevice {
217 "m.dummy" => super::dummy,
218 "m.room_key" => super::room_key,
219 #[cfg(feature = "unstable-msc4268")]
220 #[ruma_enum(alias = "m.room_key_bundle")]
221 "io.element.msc4268.room_key_bundle" => super::room_key_bundle,
222 "m.room_key_request" => super::room_key_request,
223 "m.room_key.withheld" => super::room_key::withheld,
224 "m.forwarded_room_key" => super::forwarded_room_key,
225 "m.key.verification.request" => super::key::verification::request,
226 "m.key.verification.ready" => super::key::verification::ready,
227 "m.key.verification.start" => super::key::verification::start,
228 "m.key.verification.cancel" => super::key::verification::cancel,
229 "m.key.verification.accept" => super::key::verification::accept,
230 "m.key.verification.key" => super::key::verification::key,
231 "m.key.verification.mac" => super::key::verification::mac,
232 "m.key.verification.done" => super::key::verification::done,
233 "m.room.encrypted" => super::room::encrypted,
234 "m.secret.request"=> super::secret::request,
235 "m.secret.send" => super::secret::send,
236 #[cfg(feature = "unstable-msc4385")]
237 #[ruma_enum(alias = "m.secret.push")]
238 "io.element.msc4385.secret.push" => super::secret::push,
239 #[cfg(feature = "unstable-msc4471")]
240 #[ruma_enum(alias = "m.stream.subscribe")]
241 "org.matrix.msc4471.stream.subscribe" => super::stream::subscribe,
242 #[cfg(feature = "unstable-msc4471")]
243 #[ruma_enum(alias = "m.stream.cancel")]
244 "org.matrix.msc4471.stream.cancel" => super::stream::cancel,
245 #[cfg(feature = "unstable-msc4471")]
246 #[ruma_enum(alias = "m.stream.update")]
247 "org.matrix.msc4471.stream.update" => super::stream::update,
248 }
249}
250
251macro_rules! timeline_event_accessors {
252 (
253 $(
254 #[doc = $docs:literal]
255 pub fn $field:ident(&self) -> $ty:ty;
256 )*
257 ) => {
258 $(
259 #[doc = $docs]
260 pub fn $field(&self) -> $ty {
261 match self {
262 Self::MessageLike(ev) => ev.$field(),
263 Self::State(ev) => ev.$field(),
264 }
265 }
266 )*
267 };
268}
269
270#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
272#[derive(Clone, Debug, EventEnumFromEvent)]
273pub enum AnyTimelineEvent {
274 MessageLike(AnyMessageLikeEvent),
276
277 State(AnyStateEvent),
279}
280
281impl AnyTimelineEvent {
282 timeline_event_accessors! {
283 pub fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch;
285
286 pub fn room_id(&self) -> &RoomId;
288
289 pub fn event_id(&self) -> &EventId;
291
292 pub fn sender(&self) -> &UserId;
294
295 pub fn transaction_id(&self) -> Option<&TransactionId>;
297
298 pub fn is_redacted(&self) -> bool;
300 }
301
302 pub fn event_type(&self) -> TimelineEventType {
304 match self {
305 Self::MessageLike(e) => e.event_type().into(),
306 Self::State(e) => e.event_type().into(),
307 }
308 }
309}
310
311#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
315#[derive(Clone, Debug, EventEnumFromEvent)]
316pub enum AnySyncTimelineEvent {
317 MessageLike(AnySyncMessageLikeEvent),
319
320 State(AnySyncStateEvent),
322}
323
324impl AnySyncTimelineEvent {
325 timeline_event_accessors! {
326 pub fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch;
328
329 pub fn event_id(&self) -> &EventId;
331
332 pub fn sender(&self) -> &UserId;
334
335 pub fn transaction_id(&self) -> Option<&TransactionId>;
337
338 pub fn is_redacted(&self) -> bool;
340 }
341
342 pub fn event_type(&self) -> TimelineEventType {
344 match self {
345 Self::MessageLike(e) => e.event_type().into(),
346 Self::State(e) => e.event_type().into(),
347 }
348 }
349
350 pub fn into_full_event(self, room_id: OwnedRoomId) -> AnyTimelineEvent {
352 match self {
353 Self::MessageLike(ev) => AnyTimelineEvent::MessageLike(ev.into_full_event(room_id)),
354 Self::State(ev) => AnyTimelineEvent::State(ev.into_full_event(room_id)),
355 }
356 }
357}
358
359impl From<AnyTimelineEvent> for AnySyncTimelineEvent {
360 fn from(ev: AnyTimelineEvent) -> Self {
361 match ev {
362 AnyTimelineEvent::MessageLike(ev) => Self::MessageLike(ev.into()),
363 AnyTimelineEvent::State(ev) => Self::State(ev.into()),
364 }
365 }
366}
367
368#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
370#[derive(Clone, Debug, EventEnumFromEvent, Serialize)]
371#[serde(untagged)]
372pub enum AnyTimelineEventContent {
373 MessageLike(AnyMessageLikeEventContent),
375
376 State(AnyStateEventContent),
378}
379
380impl AnyTimelineEventContent {
381 pub fn event_type(&self) -> TimelineEventType {
383 match self {
384 Self::MessageLike(content) => {
385 <AnyMessageLikeEventContent as crate::MessageLikeEventContent>::event_type(content)
386 .into()
387 }
388 Self::State(content) => {
389 <AnyStateEventContent as crate::StateEventContent>::event_type(content).into()
390 }
391 }
392 }
393}
394
395impl JsonCastable<AnyTimelineEventContent> for AnyMessageLikeEventContent {}
396impl JsonCastable<AnyTimelineEventContent> for AnyStateEventContent {}
397
398#[derive(Deserialize)]
399#[allow(clippy::exhaustive_structs)]
400struct EventDeHelper {
401 state_key: Option<de::IgnoredAny>,
402}
403
404impl<'de> Deserialize<'de> for AnyTimelineEvent {
405 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
406 where
407 D: de::Deserializer<'de>,
408 {
409 let json = Box::<RawJsonValue>::deserialize(deserializer)?;
410 let EventDeHelper { state_key } = from_raw_json_value(&json)?;
411
412 if state_key.is_some() {
413 Ok(AnyTimelineEvent::State(from_raw_json_value(&json)?))
414 } else {
415 Ok(AnyTimelineEvent::MessageLike(from_raw_json_value(&json)?))
416 }
417 }
418}
419
420impl<'de> Deserialize<'de> for AnySyncTimelineEvent {
421 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
422 where
423 D: de::Deserializer<'de>,
424 {
425 let json = Box::<RawJsonValue>::deserialize(deserializer)?;
426 let EventDeHelper { state_key } = from_raw_json_value(&json)?;
427
428 if state_key.is_some() {
429 Ok(AnySyncTimelineEvent::State(from_raw_json_value(&json)?))
430 } else {
431 Ok(AnySyncTimelineEvent::MessageLike(from_raw_json_value(&json)?))
432 }
433 }
434}
435
436impl AnyMessageLikeEventContent {
437 pub fn relation(&self) -> Option<encrypted::Relation> {
442 #[cfg(feature = "unstable-msc3489")]
443 use super::beacon::BeaconEventContent;
444 use super::key::verification::{
445 accept::KeyVerificationAcceptEventContent, cancel::KeyVerificationCancelEventContent,
446 done::KeyVerificationDoneEventContent, key::KeyVerificationKeyEventContent,
447 mac::KeyVerificationMacEventContent, ready::KeyVerificationReadyEventContent,
448 start::KeyVerificationStartEventContent,
449 };
450 #[cfg(feature = "unstable-msc3381")]
451 use super::poll::{
452 end::PollEndEventContent, response::PollResponseEventContent,
453 unstable_end::UnstablePollEndEventContent,
454 unstable_response::UnstablePollResponseEventContent,
455 };
456
457 match self {
458 #[rustfmt::skip]
459 Self::KeyVerificationReady(KeyVerificationReadyEventContent { relates_to, .. })
460 | Self::KeyVerificationStart(KeyVerificationStartEventContent { relates_to, .. })
461 | Self::KeyVerificationCancel(KeyVerificationCancelEventContent { relates_to, .. })
462 | Self::KeyVerificationAccept(KeyVerificationAcceptEventContent { relates_to, .. })
463 | Self::KeyVerificationKey(KeyVerificationKeyEventContent { relates_to, .. })
464 | Self::KeyVerificationMac(KeyVerificationMacEventContent { relates_to, .. })
465 | Self::KeyVerificationDone(KeyVerificationDoneEventContent { relates_to, .. }) => {
466 Some(encrypted::Relation::Reference(relates_to.clone()))
467 },
468 Self::Reaction(ev) => Some(encrypted::Relation::Annotation(ev.relates_to.clone())),
469 Self::RoomEncrypted(ev) => ev.relates_to.clone(),
470 Self::RoomMessage(ev) => ev.relates_to.clone().map(Into::into),
471 #[cfg(feature = "unstable-msc1767")]
472 Self::Message(ev) => ev.relates_to.clone().map(Into::into),
473 #[cfg(feature = "unstable-msc3954")]
474 Self::Emote(ev) => ev.relates_to.clone().map(Into::into),
475 #[cfg(feature = "unstable-msc3956")]
476 Self::Encrypted(ev) => ev.relates_to.clone(),
477 #[cfg(feature = "unstable-msc3245")]
478 Self::Voice(ev) => ev.relates_to.clone().map(Into::into),
479 #[cfg(feature = "unstable-msc3927")]
480 Self::Audio(ev) => ev.relates_to.clone().map(Into::into),
481 #[cfg(feature = "unstable-msc3488")]
482 Self::Location(ev) => ev.relates_to.clone().map(Into::into),
483 #[cfg(feature = "unstable-msc3551")]
484 Self::File(ev) => ev.relates_to.clone().map(Into::into),
485 #[cfg(feature = "unstable-msc3552")]
486 Self::Image(ev) => ev.relates_to.clone().map(Into::into),
487 #[cfg(feature = "unstable-msc3553")]
488 Self::Video(ev) => ev.relates_to.clone().map(Into::into),
489 #[cfg(feature = "unstable-msc3381")]
490 Self::PollResponse(PollResponseEventContent { relates_to, .. })
491 | Self::UnstablePollResponse(UnstablePollResponseEventContent { relates_to, .. })
492 | Self::PollEnd(PollEndEventContent { relates_to, .. })
493 | Self::UnstablePollEnd(UnstablePollEndEventContent { relates_to, .. }) => {
494 Some(encrypted::Relation::Reference(relates_to.clone()))
495 }
496 #[cfg(feature = "unstable-msc3489")]
497 Self::Beacon(BeaconEventContent { relates_to, .. }) => {
498 Some(encrypted::Relation::Reference(relates_to.clone()))
499 }
500 #[cfg(feature = "unstable-msc3381")]
501 Self::UnstablePollStart(UnstablePollStartEventContent::New(content)) => {
502 content.relates_to.clone().map(Into::into)
503 }
504 #[cfg(feature = "unstable-msc3381")]
505 Self::UnstablePollStart(UnstablePollStartEventContent::Replacement(content)) => {
506 Some(encrypted::Relation::Replacement(Replacement::new(
507 content.relates_to.event_id.clone(),
508 )))
509 }
510 #[cfg(feature = "unstable-msc3381")]
511 Self::PollStart(PollStartEventContent { relates_to, .. }) => {
512 relates_to.clone().map(Into::into)
513 }
514 #[cfg(feature = "unstable-msc4075")]
515 Self::CallNotify(_) => None,
516 #[cfg(feature = "unstable-msc4075")]
517 Self::RtcNotification(ev) => ev.relates_to.clone().map(encrypted::Relation::Reference),
518 #[cfg(feature = "unstable-msc4310")]
519 Self::RtcDecline(ev) => Some(encrypted::Relation::Reference(ev.relates_to.clone())),
520 Self::CallSdpStreamMetadataChanged(_)
521 | Self::CallNegotiate(_)
522 | Self::CallReject(_)
523 | Self::CallSelectAnswer(_)
524 | Self::CallAnswer(_)
525 | Self::CallInvite(_)
526 | Self::CallHangup(_)
527 | Self::CallCandidates(_)
528 | Self::RoomRedaction(_)
529 | Self::Sticker(_)
530 | Self::_Custom { .. } => None,
531 }
532 }
533}