Skip to main content

ics_core/profile/
microsoft.rs

1//! Microsoft / Outlook profile bundle (`X-MICROSOFT-CDO-*`, `X-MICROSOFT-*`).
2//!
3//! Houses the typed `MsBusyStatus` (RFC `TRANSP` has 2 values; Microsoft's
4//! busy state has 5 — they are not interchangeable, which is why this
5//! sits in a vendor bundle, not on `VEvent` directly).
6
7use serde::Serialize;
8
9use crate::raw::RawProperty;
10
11/// Property name prefixes owned by this profile. Longest match wins per
12/// ADR-001 rule 3.
13pub const PREFIXES: &[&str] = &["X-MICROSOFT-CDO-", "X-MICROSOFT-"];
14
15/// True if `name` starts with any of this profile's registered prefixes.
16pub fn owns_property(name: &str) -> bool {
17    super::matches_prefixes(name, PREFIXES)
18}
19
20/// Microsoft's `X-MICROSOFT-CDO-BUSYSTATUS` value space.
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
22#[serde(rename_all = "lowercase")]
23pub enum MsBusyStatus {
24    Free,
25    Tentative,
26    Busy,
27    Oof,
28    #[serde(rename = "working")]
29    WorkingElsewhere,
30}
31
32impl MsBusyStatus {
33    /// Derive the matching RFC 5545 `TRANSP` value. Used as a fallback
34    /// by the formatter when `VEvent.transp` is `None`.
35    pub fn transp(self) -> &'static str {
36        match self {
37            MsBusyStatus::Free => "TRANSPARENT",
38            _ => "OPAQUE",
39        }
40    }
41
42    pub fn cdo_value(self) -> &'static str {
43        match self {
44            MsBusyStatus::Free => "FREE",
45            MsBusyStatus::Tentative => "TENTATIVE",
46            MsBusyStatus::Busy => "BUSY",
47            MsBusyStatus::Oof => "OOF",
48            MsBusyStatus::WorkingElsewhere => "WORKINGELSEWHERE",
49        }
50    }
51
52    pub fn from_cdo(s: &str) -> Option<Self> {
53        match s {
54            "FREE" => Some(MsBusyStatus::Free),
55            "TENTATIVE" => Some(MsBusyStatus::Tentative),
56            "BUSY" => Some(MsBusyStatus::Busy),
57            "OOF" => Some(MsBusyStatus::Oof),
58            "WORKINGELSEWHERE" => Some(MsBusyStatus::WorkingElsewhere),
59            _ => None,
60        }
61    }
62}
63
64/// Microsoft event-level extension bundle (ADR-001 Option B).
65///
66/// `unrecognized` holds `X-MICROSOFT-*` properties whose specific name is
67/// not yet typed. Promoting one of them into a typed field (in a future
68/// step) is intra-bundle and never changes the `VEvent.unknown` slot.
69#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
70pub struct EventExtensions {
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub busystatus: Option<MsBusyStatus>,
73    #[serde(skip_serializing_if = "Vec::is_empty")]
74    pub unrecognized: Vec<RawProperty>,
75}