Skip to main content

daaki_imap/types/
notify.rs

1//! IMAP NOTIFY extension types (RFC 5465).
2//!
3//! RFC 5465 allows clients to request notifications for mailbox and message
4//! events without polling or blocking on IDLE. Event types are defined by
5//! RFC 5423 (Internet Message Store Events).
6//!
7//! All types are fully owned — no lifetime parameters.
8
9/// A mailbox filter that determines which mailboxes an event group applies to
10/// (RFC 5465 Section 6).
11///
12/// RFC 5465 Section 8 ABNF:
13/// ```text
14/// filter-mailboxes = filter-mailboxes-selected / filter-mailboxes-other
15/// filter-mailboxes-selected = "selected" / "selected-delayed"
16/// filter-mailboxes-other = "inboxes" / "personal" / "subscribed" /
17///                          ("subtree" SP one-or-more-mailbox) /
18///                          ("mailboxes" SP one-or-more-mailbox)
19/// ```
20#[non_exhaustive]
21#[derive(Debug, Clone, PartialEq, Eq, Hash)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub enum MailboxFilter {
24    /// `selected` — the currently selected mailbox; notifications delivered
25    /// immediately, including expunges (RFC 5465 Section 6.1).
26    ///
27    /// Only message events are valid with this filter. When `MessageExpunge`
28    /// is active, MSN values can change at any time so the client MUST use
29    /// UID-based commands.
30    Selected,
31
32    /// `selected-delayed` — the currently selected mailbox with delayed
33    /// `MessageExpunge` delivery (RFC 5465 Section 6.2).
34    ///
35    /// Only message events are valid with this filter. Expunge notifications
36    /// are delayed until the client issues a command that permits returning
37    /// expunge information (e.g. NOOP, IDLE).
38    SelectedDelayed,
39
40    /// `inboxes` — all selectable mailboxes where the MDA may deliver messages
41    /// (RFC 5465 Section 6.3).
42    ///
43    /// If the server cannot compute this set, it MAY treat `inboxes` as
44    /// equivalent to `personal`.
45    Inboxes,
46
47    /// `personal` — all selectable mailboxes in the user's personal
48    /// namespace(s) per RFC 2342 (RFC 5465 Section 6.4).
49    Personal,
50
51    /// `subscribed` — all mailboxes the user has subscribed to
52    /// (RFC 5465 Section 6.5).
53    ///
54    /// The server re-evaluates this set dynamically when subscriptions change.
55    Subscribed,
56
57    /// `subtree <mailbox> ...` — the specified mailbox plus all selectable
58    /// subordinate mailboxes (RFC 5465 Section 6.6).
59    ///
60    /// Must contain at least one mailbox name per ABNF
61    /// `one-or-more-mailbox` (RFC 5465 Section 8).
62    Subtree(Vec<String>),
63
64    /// `mailboxes <mailbox> ...` — one or more explicitly named mailboxes,
65    /// no wildcard expansion (RFC 5465 Section 6.7).
66    ///
67    /// Must contain at least one mailbox name per ABNF
68    /// `one-or-more-mailbox` (RFC 5465 Section 8).
69    Mailboxes(Vec<String>),
70}
71
72/// An event type that can be requested in a NOTIFY command
73/// (RFC 5465 Section 5, RFC 5423 Section 4).
74///
75/// RFC 5465 Section 8 ABNF:
76/// ```text
77/// event         = message-event / mailbox-event / user-event / event-ext
78/// message-event = ("MessageNew" [SP "(" fetch-att *(SP fetch-att) ")"])
79///               / "MessageExpunge" / "FlagChange" / "AnnotationChange"
80/// mailbox-event = "MailboxName" / "SubscriptionChange" / "MailboxMetadataChange"
81/// user-event    = "ServerMetadataChange"
82/// ```
83#[non_exhaustive]
84#[derive(Debug, Clone, PartialEq, Eq, Hash)]
85#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
86pub enum NotifyEvent {
87    // --- Message events (RFC 5465 Sections 5.1–5.3, RFC 5423 Section 4.1–4.2) ---
88    /// `MessageNew` — new message delivered or appended
89    /// (RFC 5465 Section 5.2, RFC 5423 Section 4.1).
90    ///
91    /// For the selected mailbox: server sends EXISTS then FETCH with the
92    /// requested attributes. For other mailboxes: server sends STATUS with
93    /// UIDNEXT and MESSAGES.
94    ///
95    /// The optional fetch attributes are only valid with `selected` or
96    /// `selected-delayed` mailbox filters (RFC 5465 Section 5.2).
97    MessageNew {
98        /// Optional FETCH attributes to include with new-message notifications
99        /// (RFC 5465 Section 5.2). Only valid for `selected`/`selected-delayed`.
100        /// Each string is a raw FETCH attribute (e.g. `"UID"`, `"FLAGS"`,
101        /// `"BODY.PEEK[HEADER.FIELDS (From To Subject)]"`).
102        fetch_attrs: Vec<String>,
103    },
104
105    /// `MessageExpunge` — message expunged or expired
106    /// (RFC 5465 Section 5.3, RFC 5423 Section 4.1).
107    ///
108    /// MUST always be specified together with `MessageNew` (RFC 5465 Section 5.2).
109    MessageExpunge,
110
111    /// `FlagChange` — message flags changed
112    /// (RFC 5465 Section 5.1, RFC 5423 Section 4.2).
113    ///
114    /// Requires both `MessageNew` and `MessageExpunge` to also be specified
115    /// (RFC 5465 Section 5.1).
116    FlagChange,
117
118    /// `AnnotationChange` — per-message annotation changed
119    /// (RFC 5465 Section 5.1).
120    ///
121    /// Requires both `MessageNew` and `MessageExpunge` to also be specified
122    /// (RFC 5465 Section 5.1).
123    AnnotationChange,
124
125    // --- Mailbox events (RFC 5465 Sections 5.4–5.6, RFC 5423 Section 4.4) ---
126    /// `MailboxName` — mailbox created, deleted, or renamed
127    /// (RFC 5465 Section 5.4, RFC 5423 Section 4.4).
128    ///
129    /// Server sends unsolicited LIST responses. On rename, the LIST includes
130    /// an `OLDNAME` extended data item.
131    MailboxName,
132
133    /// `SubscriptionChange` — mailbox subscribed or unsubscribed
134    /// (RFC 5465 Section 5.5, RFC 5423 Section 4.4).
135    ///
136    /// Server sends unsolicited LIST response with accurate `\Subscribed`
137    /// attribute presence.
138    SubscriptionChange,
139
140    /// `MailboxMetadataChange` — per-mailbox metadata annotation changed
141    /// (RFC 5465 Section 5.6).
142    ///
143    /// Server sends unsolicited METADATA response per RFC 5464 Section 4.4.2.
144    /// Optional unless the server implements METADATA (RFC 5464).
145    MailboxMetadataChange,
146
147    // --- User events (RFC 5465 Section 5.7) ---
148    /// `ServerMetadataChange` — server-level metadata annotation changed
149    /// (RFC 5465 Section 5.7).
150    ///
151    /// Server sends unsolicited METADATA response with empty mailbox name.
152    /// Optional unless the server implements METADATA or METADATA-SERVER.
153    ServerMetadataChange,
154
155    // --- Extension events (RFC 5465 Section 8) ---
156    /// Unrecognized event type — preserved verbatim for forward compatibility
157    /// (RFC 5465 Section 8: `event-ext = atom`).
158    Other(String),
159}
160
161/// A group of events to monitor on a set of mailboxes
162/// (RFC 5465 Section 8).
163///
164/// RFC 5465 Section 8 ABNF:
165/// ```text
166/// event-group = "(" filter-mailboxes SP events ")"
167/// events      = ("(" event *(SP event) ")") / "NONE"
168/// ```
169#[non_exhaustive]
170#[derive(Debug, Clone, PartialEq, Eq, Hash)]
171#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
172pub struct NotifyEventGroup {
173    /// Which mailboxes this event group applies to (RFC 5465 Section 6).
174    pub filter: MailboxFilter,
175
176    /// Events to monitor. An empty Vec means `NONE` — no events for this
177    /// filter (RFC 5465 Section 8).
178    pub events: Vec<NotifyEvent>,
179}
180
181impl NotifyEventGroup {
182    /// Create a new event group for the given mailbox filter and events
183    /// (RFC 5465 Section 8).
184    pub fn new(filter: MailboxFilter, events: Vec<NotifyEvent>) -> Self {
185        Self { filter, events }
186    }
187}
188
189/// Parameters for the `NOTIFY SET` command (RFC 5465 Section 3).
190///
191/// RFC 5465 Section 8 ABNF:
192/// ```text
193/// notify     = "NOTIFY" SP (notify-set / notify-none)
194/// notify-set = "SET" [status-indicator] SP event-groups
195/// ```
196#[non_exhaustive]
197#[derive(Debug, Clone, PartialEq, Eq, Hash)]
198#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
199pub struct NotifySetParams {
200    /// When `true`, the server sends an initial STATUS response for each
201    /// non-selected mailbox with message events before the tagged OK
202    /// (RFC 5465 Section 4, `status-indicator = SP "STATUS"`).
203    pub status: bool,
204
205    /// One or more event groups defining which events to monitor on which
206    /// mailboxes (RFC 5465 Section 3).
207    pub event_groups: Vec<NotifyEventGroup>,
208}
209
210impl NotifySetParams {
211    /// Create NOTIFY SET parameters with the given event groups
212    /// (RFC 5465 Section 3).
213    ///
214    /// `status` controls whether the server sends initial STATUS responses
215    /// for non-selected mailboxes before the tagged OK (RFC 5465 Section 4).
216    pub fn new(event_groups: Vec<NotifyEventGroup>, status: bool) -> Self {
217        Self {
218            status,
219            event_groups,
220        }
221    }
222}