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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//! # Misuse-resistant IMAP types
//!
//! The most prominent types in imap-types are [`Greeting`](response::Greeting), [`Command`](command::Command), and [`Response`](response::Response), and we use the term "message" to refer to either of them.
//! Messages can be created in different ways.
//! However, what all ways have in common is, that the API does not allow the creation of invalid ones.
//!
//! For example, all commands in IMAP are prefixed with a "tag".
//! Although IMAP's tags are just strings, they have additional rules, such as that no whitespace is allowed.
//! Thus, imap-types encapsulate them in [`Tag`](core::Tag) struct to ensure that invalid ones can't be created.
//!
//! ## Understanding and using the core types
//!
//! Similar to [`Tag`](core::Tag)s, there are more "core types" (or "string types"), such as, [`Atom`](core::Atom), [`Quoted`](core::Quoted), or [`Literal`](core::Literal).
//! Besides being used for correctness, these types play a crucial role in IMAP because they determine the IMAP protocol flow.
//! Sending a password as a literal requires a different protocol flow than sending the password as an atom or a quoted string.
//! So, even though imap-types can choose the most efficient representation for a datum automatically, it's good to become familiar with the [`core`] module at some point to master the IMAP protocol.
//!
//! ## Construction of messages
//!
//! imap-types relies a lot on the standard conversion traits, i.e., [`From`], [`TryFrom`], [`Into`], and [`TryInto`].
//! Make good use of them.
//! More convenient constructors are available for types that are more cumbersome to create.
//!
//! Note: When you are *sure* that the thing you want to create is valid, you can unlock various `unvalidated(...)` functions through the `unvalidated` feature.
//! This allows us to bypass certain checks in release builds.
//!
//! ### Example
//!
//! ```
//! use imap_types::{
//!     command::{Command, CommandBody},
//!     core::Tag,
//! };
//!
//! // # Variant 1
//! // Create a `Command` with `tag` "A123" and `body` "NOOP".
//! // (Note: `Command::new()` returns `Err(...)` when the tag is invalid.)
//! let cmd = Command::new("A123", CommandBody::Noop).unwrap();
//!
//! // # Variant 2
//! // Create a `CommandBody` first and finalize it into
//! // a `Command` by attaching a tag later.
//! let cmd = CommandBody::Noop.tag("A123").unwrap();
//!
//! // # Variant 3
//! // Create a `Command` directly.
//! let cmd = Command {
//!     tag: Tag::try_from("A123").unwrap(),
//!     body: CommandBody::Noop,
//! };
//! ```
//!
//! ## More complex messages
//!
//! ### Example
//!
//! The following example is a server fetch response containing the size and MIME structure of a message with the sequence number (or UID) 42.
//!
//! ```
//! use std::{borrow::Cow, num::NonZeroU32};
//!
//! use imap_types::{
//!     body::{BasicFields, Body, BodyStructure, SinglePartExtensionData, SpecificFields},
//!     core::{IString, NString, NonEmptyVec},
//!     fetch::MessageDataItem,
//!     response::{Data, Response},
//! };
//!
//! let fetch = {
//!     let data = Data::Fetch {
//!         seq: NonZeroU32::new(42).unwrap(),
//!         items: NonEmptyVec::try_from(vec![
//!             MessageDataItem::Rfc822Size(1337),
//!             MessageDataItem::Body(BodyStructure::Single {
//!                 body: Body {
//!                     basic: BasicFields {
//!                         parameter_list: vec![],
//!                         id: NString(None),
//!                         description: NString(Some(
//!                             IString::try_from("Important message.").unwrap(),
//!                         )),
//!                         content_transfer_encoding: IString::try_from("base64").unwrap(),
//!                         size: 512,
//!                     },
//!                     specific: SpecificFields::Basic {
//!                         r#type: IString::try_from("text").unwrap(),
//!                         subtype: IString::try_from("html").unwrap(),
//!                     },
//!                 },
//!                 extension_data: None,
//!             }),
//!         ])
//!         .unwrap(),
//!     };
//!
//!     Response::Data(data)
//! };
//! ```
//!
//! # Supported IMAP extensions
//!
//! |Description                                                  |
//! |-------------------------------------------------------------|
//! |IMAP4 Non-synchronizing Literals ([RFC 2088], [RFC 7888])    |
//! |IMAP MOVE Extension ([RFC 6851])                             |
//! |IMAP UNSELECT command ([RFC 3691])                           |
//! |IMAP Extension for SASL Initial Client Response ([RFC 4959]) |
//! |The IMAP COMPRESS Extension ([RFC 4978])                     |
//! |The IMAP ENABLE Extension ([RFC 5161])                       |
//! |IMAP4 IDLE command ([RFC 2177])                              |
//! |IMAP QUOTA Extension ([RFC 9208])                            |
//!
//! # Features
//!
//! This crate uses the following features to enable experimental IMAP extensions:
//!
//! |Feature              |Description                                                                          |Status    |
//! |---------------------|-------------------------------------------------------------------------------------|----------|
//! |ext_condstore_qresync|Quick Flag Changes Resynchronization and Quick Mailbox Resynchronization ([RFC 7162])|Unfinished|
//! |ext_login_referrals  |IMAP4 Login Referrals ([RFC 2221])                                                   |Unfinished|
//! |ext_mailbox_referrals|IMAP4 Mailbox Referrals ([RFC 2193])                                                 |Unfinished|
//! |starttls             |IMAP4rev1 ([RFC 3501]; section 6.2.1)                                                |          |
//!
//! STARTTLS is not an IMAP extension but feature-gated because it [should be avoided](https://nostarttls.secvuln.info/).
//! For better performance and security, use "implicit TLS", i.e., IMAP-over-TLS on port 993, and don't use STARTTLS at all.
//!
//! Furthermore, imap-types uses the following features to facilitate interoperability:
//!
//! | Feature          | Description                                                    | Enabled by default |
//! |------------------|----------------------------------------------------------------|--------------------|
//! | arbitrary        | Derive `Arbitrary` implementations.                            | No                 |
//! | bounded-static   | Derive `ToStatic/IntoStatic` implementations.                  | No                 |
//! | serde            | Derive `serde`s `Serialize` and `Deserialize` implementations. | No                 |
//! | unvalidated      | Unlock `unvalidated` constructors.                             | No                 |
//!
//! When using `arbitrary`, all types defined in imap-types implement the [Arbitrary] trait to ease testing.
//! This is used, for example, to generate instances during fuzz-testing.
//! (See, e.g., `imap-types/fuzz/fuzz_targets/to_static.rs`)
//! When using `bounded-static`, all types provide a `to_static` and `into_static` method that converts a type into its "owned" variant.
//! This is useful when you want to pass objects around, e.g., into other threads, a vector, etc.
//! When the `serde` feature is used, all types implement [Serde](https://serde.rs/)'s [Serialize](https://docs.serde.rs/serde/trait.Serialize.html) and
//! [Deserialize](https://docs.serde.rs/serde/trait.Deserialize.html) traits. (Try running `cargo run --example serde_json`.)
//!
//! [Arbitrary]: https://docs.rs/arbitrary/1.0.1/arbitrary/trait.Arbitrary.html
//! [parse_command]: https://github.com/duesee/imap-codec/blob/main/imap-codec/examples/parse_command.rs
//! [RFC 2088]: https://datatracker.ietf.org/doc/html/rfc2088
//! [RFC 2177]: https://datatracker.ietf.org/doc/html/rfc2177
//! [RFC 2193]: https://datatracker.ietf.org/doc/html/rfc2193
//! [RFC 2221]: https://datatracker.ietf.org/doc/html/rfc2221
//! [RFC 3501]: https://datatracker.ietf.org/doc/html/rfc3501
//! [RFC 3691]: https://datatracker.ietf.org/doc/html/rfc3691
//! [RFC 4959]: https://datatracker.ietf.org/doc/html/rfc4959
//! [RFC 4978]: https://datatracker.ietf.org/doc/html/rfc4978
//! [RFC 5161]: https://datatracker.ietf.org/doc/html/rfc5161
//! [RFC 6851]: https://datatracker.ietf.org/doc/html/rfc6851
//! [RFC 7162]: https://datatracker.ietf.org/doc/html/rfc7162
//! [RFC 7888]: https://datatracker.ietf.org/doc/html/rfc7888
//! [RFC 9208]: https://datatracker.ietf.org/doc/html/rfc9208

#![forbid(unsafe_code)]
#![deny(missing_debug_implementations)]
// TODO(#313)
// #![deny(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]

#[cfg(feature = "arbitrary")]
mod arbitrary;
pub mod auth;
pub mod body;
pub mod command;
pub mod core;
pub mod datetime;
pub mod envelope;
pub mod error;
pub mod extensions;
pub mod fetch;
pub mod flag;
pub mod mailbox;
pub mod response;
pub mod search;
pub mod secret;
pub mod sequence;
pub mod state;
pub mod status;
pub mod utils;

#[cfg(feature = "bounded-static")]
pub use bounded_static;