imap_types/state.rs
1//! IMAP protocol state.
2//!
3//! "Once the connection between client and server is established, an IMAP4rev1 connection is in one of four states.
4//! The initial state is identified in the server greeting.
5//! Most commands are only valid in certain states.
6//! It is a protocol error for the client to attempt a command while the connection is in an inappropriate state,
7//! and the server will respond with a BAD or NO (depending upon server implementation) command completion result." ([RFC 3501](https://www.rfc-editor.org/rfc/rfc3501.html))
8//!
9//! ```text
10//! +----------------------+
11//! |connection established|
12//! +----------------------+
13//! ||
14//! \/
15//! +--------------------------------------+
16//! | server greeting |
17//! +--------------------------------------+
18//! || (1) || (2) || (3)
19//! \/ || ||
20//! +-----------------+ || ||
21//! |Not Authenticated| || ||
22//! +-----------------+ || ||
23//! || (7) || (4) || ||
24//! || \/ \/ ||
25//! || +----------------+ ||
26//! || | Authenticated |<=++ ||
27//! || +----------------+ || ||
28//! || || (7) || (5) || (6) ||
29//! || || \/ || ||
30//! || || +--------+ || ||
31//! || || |Selected|==++ ||
32//! || || +--------+ ||
33//! || || || (7) ||
34//! \/ \/ \/ \/
35//! +--------------------------------------+
36//! | Logout |
37//! +--------------------------------------+
38//! ||
39//! \/
40//! +-------------------------------+
41//! |both sides close the connection|
42//! +-------------------------------+
43//!
44//! (1) connection without pre-authentication (OK greeting)
45//! (2) pre-authenticated connection (PREAUTH greeting)
46//! (3) rejected connection (BYE greeting)
47//! (4) successful LOGIN or AUTHENTICATE command
48//! (5) successful SELECT or EXAMINE command
49//! (6) CLOSE command, or failed SELECT or EXAMINE command
50//! (7) LOGOUT command, server shutdown, or connection closed
51//! ```
52
53#[cfg(feature = "bounded-static")]
54use bounded_static::ToStatic;
55#[cfg(feature = "serde")]
56use serde::{Deserialize, Serialize};
57
58use crate::{core::Tag, mailbox::Mailbox};
59
60/// State of the IMAP4rev1 connection.
61#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
62#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
63#[derive(Clone, Debug, Eq, PartialEq)]
64pub enum State<'a> {
65 Greeting,
66
67 /// The client MUST supply authentication credentials before most commands will be permitted.
68 /// This state is entered when a connection starts unless the connection has been pre-authenticated.
69 NotAuthenticated,
70
71 /// The client is authenticated and MUST select a mailbox to access before commands that affect messages will be permitted.
72 /// This state is entered when a pre-authenticated connection starts, when acceptable authentication credentials have been provided,
73 /// after an error in selecting a mailbox, or after a successful CLOSE command.
74 Authenticated,
75
76 /// A mailbox has been selected to access.
77 /// This state is entered when a mailbox has been successfully selected.
78 Selected(Mailbox<'a>),
79
80 /// The connection is being terminated.
81 /// This state can be entered as a result of a client request (via the LOGOUT command) or by unilateral action on the part of either the client or server.
82 ///
83 /// If the client requests the logout state, the server MUST send an untagged BYE response and a tagged OK response to the LOGOUT command before the server closes the connection;
84 /// and the client MUST read the tagged OK response to the LOGOUT command before the client closes the connection.
85 ///
86 /// A server MUST NOT unilaterally close the connection without sending an untagged BYE response that contains the reason for having done so.
87 /// A client SHOULD NOT unilaterally close the connection, and instead SHOULD issue a LOGOUT command.
88 /// If the server detects that the client has unilaterally closed the connection, the server MAY omit the untagged BYE response and simply close its connection.
89 Logout,
90
91 IdleAuthenticated(Tag<'a>),
92
93 IdleSelected(Tag<'a>, Mailbox<'a>),
94}
95
96#[cfg(test)]
97mod tests {
98 #[cfg(feature = "bounded-static")]
99 use bounded_static::{IntoBoundedStatic, ToBoundedStatic};
100
101 use super::*;
102 use crate::{core::Tag, mailbox::Mailbox};
103
104 #[test]
105 fn test_conversion() {
106 let tests = [
107 State::Greeting,
108 State::NotAuthenticated,
109 State::Authenticated,
110 State::Selected(Mailbox::Inbox),
111 State::Logout,
112 State::IdleAuthenticated(Tag::try_from("A").unwrap()),
113 State::IdleSelected(Tag::try_from("A").unwrap(), Mailbox::Inbox),
114 ];
115
116 for _test in tests {
117 #[cfg(feature = "bounded-static")]
118 {
119 let test_to_static = _test.to_static();
120 assert_eq!(_test, test_to_static);
121
122 let test_into_static = _test.into_static();
123 assert_eq!(test_to_static, test_into_static);
124 }
125 }
126 }
127}