1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//! # IMAP protocol library
//!
//! imap-codec provides complete and detailed parsing and construction of [IMAP4rev1] commands and responses.
//! It is based on [imap-types] and extends it with parsing support using [nom].
//!
//! ## Example
//!
//! ```rust
//! use imap_codec::{
//!     codec::{Decode, Encode},
//!     command::Command,
//! };
//!
//! // We assume here that the message is already complete.
//! let input = b"ABCD UID FETCH 1,2:* (BODY.PEEK[1.2.3.4.MIME]<42.1337>)\r\n";
//!
//! let (_remainder, parsed) = Command::decode(input).unwrap();
//! println!("// Parsed:");
//! println!("{parsed:#?}");
//!
//! let serialized = parsed.encode().dump();
//!
//! // Not every IMAP message is valid UTF-8.
//! // We ignore that here, so that we can print the message.
//! let serialized = String::from_utf8(serialized).unwrap();
//! println!("// Serialized:");
//! println!("// {serialized}");
//! ```
//!
//! ## Decoding
//!
//! Parsing is implemented through the [`Decode`](crate::codec::Decode) trait.
//! The main entry points for parsing are
//! [`Greeting::decode(...)`](response::Greeting#method.decode) (to parse the first message from a server),
//! [`Command::decode(...)`](command::Command#method.decode) (to parse commands from a client), and
//! [`Response::decode(...)`](response::Response#method.decode) (to parse responses or results from a server).
//! Note, however, that certain message flows require other parsers as well.
//! Every parser takes an input (`&[u8]`) and produces a remainder and a parsed value.
//!
//! ### Example
//!
//! Have a look at the [parse_command](https://github.com/duesee/imap-codec/blob/main/examples/parse_command.rs) example to see how a real-world application could decode IMAP.
//!
//! IMAP literals make separating the parsing logic from the application logic difficult.
//! When a server recognizes a literal (e.g. "{42}"), it first needs to agree to receive more data by sending a so-called "continuation request" (`+ ...`).
//! Without a continuation request, a client won't send more data, and the parser on the server would always return `Incomplete(42)`.
//! This makes real-world decoding of IMAP a bit more elaborate.
//!
//! ## Encoding
//!
//! The [`Encode::encode(...)`](codec::Encode::encode) method will return an instance of [`Encoded`](codec::Encoded)
//! that facilitates handling of literals. The idea is that the encoder not only "dumps" the final serialization of a message but can be iterated over.
//!
//! ### Example
//!
//! ```rust
//! #[cfg(feature = "ext_literal")]
//! use imap_codec::core::LiteralMode;
//! use imap_codec::{
//!     codec::{Decode, Encode, Fragment},
//!     command::{Command, CommandBody},
//! };
//!
//! let command = Command::new("A1", CommandBody::login("Alice", "Pa²²W0rD").unwrap()).unwrap();
//!
//! for fragment in command.encode() {
//!     match fragment {
//!         Fragment::Line { data } => {
//!             // A line that is ready to be send.
//!             println!("C: {}", String::from_utf8(data).unwrap());
//!         }
//!         #[cfg(not(feature = "ext_literal"))]
//!         Fragment::Literal { data } => {
//!             // Wait for a continuation request.
//!             println!("S: + ...")
//!         }
//!         #[cfg(feature = "ext_literal")]
//!         Fragment::Literal { data, mode } => match mode {
//!             LiteralMode::Sync => {
//!                 // Wait for a continuation request.
//!                 println!("S: + ...")
//!             }
//!             LiteralMode::NonSync => {
//!                 // We don't need to wait for a continuation request
//!                 // as the server will also not send it.
//!             }
//!         },
//!     }
//! }
//! ```
//!
//! Output of example:
//!
//! ```imap
//! C: A1 LOGIN alice {10}
//! S: + ...
//! C: Pa²²W0rD
//! ```
//!
//! # Features
//!
//! imap-codec forwards many features to imap-types. See [imap-types features] for a comprehensive list.
//!
//! In addition, imap-codec defines the following features:
//!
//! | Feature               | Description                    | Enabled by default |
//! |-----------------------|--------------------------------|--------------------|
//! | quirk_crlf_relaxed    | Make `\r` in `\r\n` optional.  | No                 |
//! | quirk_rectify_numbers | Rectify (invalid) numbers.     | No                 |
//! | quirk_missing_text    | Rectify missing `text` element.| No                 |
//! | tokio                 | Tokio support.                 | No                 |
//!
//! ## Quirks
//!
//! Features starting with `quirk_` are used to cope with existing interoperability issues.
//! Unfortunately, we already observed some standard violations, such as, negative numbers, and missing syntax elements.
//! Our policy is as follows: If we see an interoperability issue, we file an issue in the corresponding implementation.
//! If, for any reason, the issue cannot be fixed, *and* the implementation is "important enough", e.g.,  because a user of
//! imap-codec can't otherwise access their emails, we may add a `quirk_` feature to quickly resolve the problem.
//! Of course, imap-codec should never violate the IMAP standard itself. So, we need to do this carefully.
//!
//! ## Tokio support
//!
//! The `tokio` feature unlocks an implementation of [tokio_util::codec].
//! See the [tokio client] and [tokio server] demos.
//!
//! [imap-types]: imap_types
//! [imap-types features]: ../imap_types/index.html#features
//! [IMAP4rev1]: https://tools.ietf.org/html/rfc3501
//! [parse_command]: https://github.com/duesee/imap-codec/blob/main/examples/parse_command.rs
//! [tokio_util::codec]: https://docs.rs/tokio-util/latest/tokio_util/codec/index.html
//! [tokio client]: https://github.com/duesee/imap-codec/tree/main/assets/demos/tokio-client
//! [tokio server]: https://github.com/duesee/imap-codec/tree/main/assets/demos/tokio-server

#![forbid(unsafe_code)]
#![deny(missing_debug_implementations)]
#![cfg_attr(docsrs, feature(doc_cfg))]

pub mod auth;
pub mod body;
pub mod codec;
pub mod command;
pub mod core;
pub mod datetime;
pub mod envelope;
#[cfg(any(
    feature = "ext_compress",
    feature = "ext_condstore_qresync",
    feature = "ext_enable",
    feature = "ext_idle",
    feature = "ext_literal",
    feature = "ext_move",
    feature = "ext_quota",
    feature = "ext_unselect",
))]
#[cfg_attr(docsrs, doc(cfg(feature = "ext_*")))]
pub mod extensions;
pub mod fetch;
pub mod flag;
pub mod mailbox;
pub mod response;
pub mod search;
pub mod section;
pub mod sequence;
pub mod status;
#[cfg(test)]
mod testing;
#[cfg(feature = "tokio")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
pub mod tokio;
pub use imap_types::{secret, state, utils};