async_imap/types/
mod.rs

1//! This module contains types used throughout the IMAP protocol.
2
3use std::borrow::Cow;
4
5/// From section [2.3.1.1 of RFC 3501](https://tools.ietf.org/html/rfc3501#section-2.3.1.1).
6///
7/// A 32-bit value assigned to each message, which when used with the unique identifier validity
8/// value (see below) forms a 64-bit value that will not refer to any other message in the mailbox
9/// or any subsequent mailbox with the same name forever.  Unique identifiers are assigned in a
10/// strictly ascending fashion in the mailbox; as each message is added to the mailbox it is
11/// assigned a higher UID than the message(s) which were added previously.  Unlike message sequence
12/// numbers, unique identifiers are not necessarily contiguous.
13///
14/// The unique identifier of a message will not change during the session, and will generally not
15/// change between sessions.  Any change of unique identifiers between sessions will be detectable
16/// using the `UIDVALIDITY` mechanism discussed below.  Persistent unique identifiers are required
17/// for a client to resynchronize its state from a previous session with the server (e.g.,
18/// disconnected or offline access clients); this is discussed further in
19/// [`IMAP-DISC`](https://tools.ietf.org/html/rfc3501#ref-IMAP-DISC).
20///
21/// Associated with every mailbox are two values which aid in unique identifier handling: the next
22/// unique identifier value and the unique identifier validity value.
23///
24/// The next unique identifier value is the predicted value that will be assigned to a new message
25/// in the mailbox.  Unless the unique identifier validity also changes (see below), the next
26/// unique identifier value will have the following two characteristics.  First, the next unique
27/// identifier value will not change unless new messages are added to the mailbox; and second, the
28/// next unique identifier value will change whenever new messages are added to the mailbox, even
29/// if those new messages are subsequently expunged.
30///
31/// > Note: The next unique identifier value is intended to provide a means for a client to
32/// > determine whether any messages have been delivered to the mailbox since the previous time it
33/// > checked this value.  It is not intended to provide any guarantee that any message will have
34/// > this unique identifier.  A client can only assume, at the time that it obtains the next
35/// > unique identifier value, that messages arriving after that time will have a UID greater than
36/// > or equal to that value.
37///
38/// The unique identifier validity value is sent in a `UIDVALIDITY` response code in an `OK`
39/// untagged response at mailbox selection time. If unique identifiers from an earlier session fail
40/// to persist in this session, the unique identifier validity value will be greater than the one
41/// used in the earlier session.
42///
43/// > Note: Ideally, unique identifiers will persist at all
44/// > times.  Although this specification recognizes that failure
45/// > to persist can be unavoidable in certain server
46/// > environments, it STRONGLY ENCOURAGES message store
47/// > implementation techniques that avoid this problem.  For
48/// > example:
49/// >
50/// >   1. Unique identifiers are strictly ascending in the
51/// >      mailbox at all times.  If the physical message store is
52/// >      re-ordered by a non-IMAP agent, this requires that the
53/// >      unique identifiers in the mailbox be regenerated, since
54/// >      the former unique identifiers are no longer strictly
55/// >      ascending as a result of the re-ordering.
56/// >   2. If the message store has no mechanism to store unique
57/// >      identifiers, it must regenerate unique identifiers at
58/// >      each session, and each session must have a unique
59/// >      `UIDVALIDITY` value.
60/// >   3. If the mailbox is deleted and a new mailbox with the
61/// >      same name is created at a later date, the server must
62/// >      either keep track of unique identifiers from the
63/// >      previous instance of the mailbox, or it must assign a
64/// >      new `UIDVALIDITY` value to the new instance of the
65/// >      mailbox.  A good `UIDVALIDITY` value to use in this case
66/// >      is a 32-bit representation of the creation date/time of
67/// >      the mailbox.  It is alright to use a constant such as
68/// >      1, but only if it guaranteed that unique identifiers
69/// >      will never be reused, even in the case of a mailbox
70/// >      being deleted (or renamed) and a new mailbox by the
71/// >      same name created at some future time.
72/// >   4. The combination of mailbox name, `UIDVALIDITY`, and `UID`
73/// >      must refer to a single immutable message on that server
74/// >      forever.  In particular, the internal date, [RFC 2822](https://tools.ietf.org/html/rfc2822)
75/// >      size, envelope, body structure, and message texts
76/// >      (RFC822, RFC822.HEADER, RFC822.TEXT, and all BODY[...]
77/// >      fetch data items) must never change.  This does not
78/// >      include message numbers, nor does it include attributes
79/// >      that can be set by a `STORE` command (e.g., `FLAGS`).
80pub type Uid = u32;
81
82/// From section [2.3.1.2 of RFC 3501](https://tools.ietf.org/html/rfc3501#section-2.3.1.2).
83///
84/// A relative position from 1 to the number of messages in the mailbox.
85/// This position is ordered by ascending unique identifier.  As
86/// each new message is added, it is assigned a message sequence number
87/// that is 1 higher than the number of messages in the mailbox before
88/// that new message was added.
89///
90/// Message sequence numbers can be reassigned during the session.  For
91/// example, when a message is permanently removed (expunged) from the
92/// mailbox, the message sequence number for all subsequent messages is
93/// decremented.  The number of messages in the mailbox is also
94/// decremented.  Similarly, a new message can be assigned a message
95/// sequence number that was once held by some other message prior to an
96/// expunge.
97///
98/// In addition to accessing messages by relative position in the
99/// mailbox, message sequence numbers can be used in mathematical
100/// calculations.  For example, if an untagged "11 EXISTS" is received,
101/// and previously an untagged "8 EXISTS" was received, three new
102/// messages have arrived with message sequence numbers of 9, 10, and 11.
103/// Another example, if message 287 in a 523 message mailbox has UID
104/// 12345, there are exactly 286 messages which have lesser UIDs and 236
105/// messages which have greater UIDs.
106pub type Seq = u32;
107
108/// Message flags.
109///
110/// With the exception of [`Flag::Custom`], these flags are system flags that are pre-defined in
111/// [RFC 3501 section 2.3.2](https://tools.ietf.org/html/rfc3501#section-2.3.2). All system flags
112/// begin with `\` in the IMAP protocol.  Certain system flags (`\Deleted` and `\Seen`) have
113/// special semantics described elsewhere.
114///
115/// A flag can be permanent or session-only on a per-flag basis. Permanent flags are those which
116/// the client can add or remove from the message flags permanently; that is, concurrent and
117/// subsequent sessions will see any change in permanent flags.  Changes to session flags are valid
118/// only in that session.
119///
120/// > Note: The `\Recent` system flag is a special case of a session flag.  `\Recent` can not be
121/// > used as an argument in a `STORE` or `APPEND` command, and thus can not be changed at all.
122#[derive(Clone, Debug, Hash, PartialEq, Eq)]
123pub enum Flag<'a> {
124    /// Message has been read
125    Seen,
126
127    /// Message has been answered
128    Answered,
129
130    /// Message is "flagged" for urgent/special attention
131    Flagged,
132
133    /// Message is "deleted" for removal by later EXPUNGE
134    Deleted,
135
136    /// Message has not completed composition (marked as a draft).
137    Draft,
138
139    /// Message is "recently" arrived in this mailbox.  This session is the first session to have
140    /// been notified about this message; if the session is read-write, subsequent sessions will
141    /// not see `\Recent` set for this message.  This flag can not be altered by the client.
142    ///
143    /// If it is not possible to determine whether or not this session is the first session to be
144    /// notified about a message, then that message will generally be considered recent.
145    ///
146    /// If multiple connections have the same mailbox selected simultaneously, it is undefined
147    /// which of these connections will see newly-arrived messages with `\Recent` set and which
148    /// will see it without `\Recent` set.
149    Recent,
150
151    /// The [`Mailbox::permanent_flags`] can include this special flag (`\*`), which indicates that
152    /// it is possible to create new keywords by attempting to store those flags in the mailbox.
153    MayCreate,
154
155    /// A non-standard user- or server-defined flag.
156    Custom(Cow<'a, str>),
157}
158
159impl Flag<'static> {
160    fn system(s: &str) -> Option<Self> {
161        match s {
162            "\\Seen" => Some(Flag::Seen),
163            "\\Answered" => Some(Flag::Answered),
164            "\\Flagged" => Some(Flag::Flagged),
165            "\\Deleted" => Some(Flag::Deleted),
166            "\\Draft" => Some(Flag::Draft),
167            "\\Recent" => Some(Flag::Recent),
168            "\\*" => Some(Flag::MayCreate),
169            _ => None,
170        }
171    }
172}
173
174impl From<String> for Flag<'_> {
175    fn from(s: String) -> Self {
176        if let Some(f) = Flag::system(&s) {
177            f
178        } else {
179            Flag::Custom(Cow::Owned(s))
180        }
181    }
182}
183
184impl<'a> From<&'a str> for Flag<'a> {
185    fn from(s: &'a str) -> Self {
186        if let Some(f) = Flag::system(s) {
187            f
188        } else {
189            Flag::Custom(Cow::Borrowed(s))
190        }
191    }
192}
193
194mod mailbox;
195pub use self::mailbox::Mailbox;
196
197mod fetch;
198pub use self::fetch::Fetch;
199
200mod name;
201pub use self::name::{Name, NameAttribute};
202
203mod capabilities;
204pub use self::capabilities::{Capabilities, Capability};
205
206/// re-exported from imap_proto;
207pub use imap_proto::StatusAttribute;
208
209mod id_generator;
210pub(crate) use self::id_generator::IdGenerator;
211
212mod response_data;
213pub(crate) use self::response_data::ResponseData;
214
215mod request;
216pub(crate) use self::request::Request;
217
218mod quota;
219pub use self::quota::*;
220
221/// Responses that the server sends that are not related to the current command.
222///
223/// [RFC 3501](https://tools.ietf.org/html/rfc3501#section-7) states that clients need to be able
224/// to accept any response at any time. These are the ones we've encountered in the wild.
225///
226/// Note that `Recent`, `Exists` and `Expunge` responses refer to the currently `SELECT`ed folder,
227/// so the user must take care when interpreting these.
228#[derive(Debug, PartialEq, Eq)]
229pub enum UnsolicitedResponse {
230    /// An unsolicited [`STATUS response`](https://tools.ietf.org/html/rfc3501#section-7.2.4).
231    Status {
232        /// The mailbox that this status response is for.
233        mailbox: String,
234        /// The attributes of this mailbox.
235        attributes: Vec<StatusAttribute>,
236    },
237
238    /// An unsolicited [`RECENT` response](https://tools.ietf.org/html/rfc3501#section-7.3.2)
239    /// indicating the number of messages with the `\Recent` flag set.  This response occurs if the
240    /// size of the mailbox changes (e.g., new messages arrive).
241    ///
242    /// > Note: It is not guaranteed that the message sequence
243    /// > numbers of recent messages will be a contiguous range of
244    /// > the highest n messages in the mailbox (where n is the
245    /// > value reported by the `RECENT` response).  Examples of
246    /// > situations in which this is not the case are: multiple
247    /// > clients having the same mailbox open (the first session
248    /// > to be notified will see it as recent, others will
249    /// > probably see it as non-recent), and when the mailbox is
250    /// > re-ordered by a non-IMAP agent.
251    /// >
252    /// > The only reliable way to identify recent messages is to
253    /// > look at message flags to see which have the `\Recent` flag
254    /// > set, or to do a `SEARCH RECENT`.
255    Recent(u32),
256
257    /// An unsolicited [`EXISTS` response](https://tools.ietf.org/html/rfc3501#section-7.3.1) that
258    /// reports the number of messages in the mailbox. This response occurs if the size of the
259    /// mailbox changes (e.g., new messages arrive).
260    Exists(u32),
261
262    /// An unsolicited [`EXPUNGE` response](https://tools.ietf.org/html/rfc3501#section-7.4.1) that
263    /// reports that the specified message sequence number has been permanently removed from the
264    /// mailbox.  The message sequence number for each successive message in the mailbox is
265    /// immediately decremented by 1, and this decrement is reflected in message sequence numbers
266    /// in subsequent responses (including other untagged `EXPUNGE` responses).
267    ///
268    /// The EXPUNGE response also decrements the number of messages in the mailbox; it is not
269    /// necessary to send an `EXISTS` response with the new value.
270    ///
271    /// As a result of the immediate decrement rule, message sequence numbers that appear in a set
272    /// of successive `EXPUNGE` responses depend upon whether the messages are removed starting
273    /// from lower numbers to higher numbers, or from higher numbers to lower numbers.  For
274    /// example, if the last 5 messages in a 9-message mailbox are expunged, a "lower to higher"
275    /// server will send five untagged `EXPUNGE` responses for message sequence number 5, whereas a
276    /// "higher to lower server" will send successive untagged `EXPUNGE` responses for message
277    /// sequence numbers 9, 8, 7, 6, and 5.
278    // TODO: the spec doesn't seem to say anything about when these may be received as unsolicited?
279    Expunge(u32),
280    /// Any other kind of unsolicted response.
281    Other(ResponseData),
282}