imap_types/lib.rs
1//! # Misuse-resistant IMAP types
2//!
3//! 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.
4//! Messages can be created in different ways.
5//! However, what all ways have in common is, that the API does not allow the creation of invalid ones.
6//!
7//! For example, all commands in IMAP are prefixed with a "tag".
8//! Although IMAP's tags are just strings, they have additional rules, such as that no whitespace is allowed.
9//! Thus, imap-types encapsulate them in [`Tag`](core::Tag) struct to ensure that invalid ones can't be created.
10//!
11//! ## Understanding and using the core types
12//!
13//! 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).
14//! Besides being used for correctness, these types play a crucial role in IMAP because they determine the IMAP protocol flow.
15//! Sending a password as a literal requires a different protocol flow than sending the password as an atom or a quoted string.
16//! 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.
17//!
18//! ## Construction of messages
19//!
20//! imap-types relies a lot on the standard conversion traits, i.e., [`From`], [`TryFrom`], [`Into`], and [`TryInto`].
21//! Make good use of them.
22//! More convenient constructors are available for types that are more cumbersome to create.
23//!
24//! Note: When you are *sure* that the thing you want to create is valid, you can unlock various `unvalidated(...)` functions through the `unvalidated` feature.
25//! This allows us to bypass certain checks in release builds.
26//!
27//! ### Example
28//!
29//! ```
30//! use imap_types::{
31//! command::{Command, CommandBody},
32//! core::Tag,
33//! };
34//!
35//! // # Variant 1
36//! // Create a `Command` with `tag` "A123" and `body` "NOOP".
37//! // (Note: `Command::new()` returns `Err(...)` when the tag is invalid.)
38//! let cmd = Command::new("A123", CommandBody::Noop).unwrap();
39//!
40//! // # Variant 2
41//! // Create a `CommandBody` first and finalize it into
42//! // a `Command` by attaching a tag later.
43//! let cmd = CommandBody::Noop.tag("A123").unwrap();
44//!
45//! // # Variant 3
46//! // Create a `Command` directly.
47//! let cmd = Command {
48//! tag: Tag::try_from("A123").unwrap(),
49//! body: CommandBody::Noop,
50//! };
51//! ```
52//!
53//! ## More complex messages
54//!
55//! ### Example
56//!
57//! The following example is a server fetch response containing the size and MIME structure of a message with the sequence number (or UID) 42.
58//!
59//! ```
60//! use std::{borrow::Cow, num::NonZeroU32};
61//!
62//! use imap_types::{
63//! body::{BasicFields, Body, BodyStructure, SinglePartExtensionData, SpecificFields},
64//! core::{IString, NString, NonEmptyVec},
65//! fetch::MessageDataItem,
66//! response::{Data, Response},
67//! };
68//!
69//! let fetch = {
70//! let data = Data::Fetch {
71//! seq: NonZeroU32::new(42).unwrap(),
72//! items: NonEmptyVec::try_from(vec![
73//! MessageDataItem::Rfc822Size(1337),
74//! MessageDataItem::Body(BodyStructure::Single {
75//! body: Body {
76//! basic: BasicFields {
77//! parameter_list: vec![],
78//! id: NString(None),
79//! description: NString(Some(
80//! IString::try_from("Important message.").unwrap(),
81//! )),
82//! content_transfer_encoding: IString::try_from("base64").unwrap(),
83//! size: 512,
84//! },
85//! specific: SpecificFields::Basic {
86//! r#type: IString::try_from("text").unwrap(),
87//! subtype: IString::try_from("html").unwrap(),
88//! },
89//! },
90//! extension_data: None,
91//! }),
92//! ])
93//! .unwrap(),
94//! };
95//!
96//! Response::Data(data)
97//! };
98//! ```
99//!
100//! # Supported IMAP extensions
101//!
102//! |Description |
103//! |-------------------------------------------------------------|
104//! |IMAP4 Non-synchronizing Literals ([RFC 2088], [RFC 7888]) |
105//! |IMAP MOVE Extension ([RFC 6851]) |
106//! |IMAP UNSELECT command ([RFC 3691]) |
107//! |IMAP Extension for SASL Initial Client Response ([RFC 4959]) |
108//! |The IMAP COMPRESS Extension ([RFC 4978]) |
109//! |The IMAP ENABLE Extension ([RFC 5161]) |
110//! |IMAP4 IDLE command ([RFC 2177]) |
111//! |IMAP QUOTA Extension ([RFC 9208]) |
112//!
113//! # Features
114//!
115//! This crate uses the following features to enable experimental IMAP extensions:
116//!
117//! |Feature |Description |Status |
118//! |---------------------|-------------------------------------------------------------------------------------|----------|
119//! |ext_condstore_qresync|Quick Flag Changes Resynchronization and Quick Mailbox Resynchronization ([RFC 7162])|Unfinished|
120//! |ext_login_referrals |IMAP4 Login Referrals ([RFC 2221]) |Unfinished|
121//! |ext_mailbox_referrals|IMAP4 Mailbox Referrals ([RFC 2193]) |Unfinished|
122//! |starttls |IMAP4rev1 ([RFC 3501]; section 6.2.1) | |
123//!
124//! STARTTLS is not an IMAP extension but feature-gated because it [should be avoided](https://nostarttls.secvuln.info/).
125//! For better performance and security, use "implicit TLS", i.e., IMAP-over-TLS on port 993, and don't use STARTTLS at all.
126//!
127//! Furthermore, imap-types uses the following features to facilitate interoperability:
128//!
129//! | Feature | Description | Enabled by default |
130//! |------------------|----------------------------------------------------------------|--------------------|
131//! | arbitrary | Derive `Arbitrary` implementations. | No |
132//! | bounded-static | Derive `ToStatic/IntoStatic` implementations. | No |
133//! | serde | Derive `serde`s `Serialize` and `Deserialize` implementations. | No |
134//! | unvalidated | Unlock `unvalidated` constructors. | No |
135//!
136//! When using `arbitrary`, all types defined in imap-types implement the [Arbitrary] trait to ease testing.
137//! This is used, for example, to generate instances during fuzz-testing.
138//! (See, e.g., `imap-types/fuzz/fuzz_targets/to_static.rs`)
139//! When using `bounded-static`, all types provide a `to_static` and `into_static` method that converts a type into its "owned" variant.
140//! This is useful when you want to pass objects around, e.g., into other threads, a vector, etc.
141//! When the `serde` feature is used, all types implement [Serde](https://serde.rs/)'s [Serialize](https://docs.serde.rs/serde/trait.Serialize.html) and
142//! [Deserialize](https://docs.serde.rs/serde/trait.Deserialize.html) traits. (Try running `cargo run --example serde_json`.)
143//!
144//! [Arbitrary]: https://docs.rs/arbitrary/1.0.1/arbitrary/trait.Arbitrary.html
145//! [parse_command]: https://github.com/duesee/imap-codec/blob/main/imap-codec/examples/parse_command.rs
146//! [RFC 2088]: https://datatracker.ietf.org/doc/html/rfc2088
147//! [RFC 2177]: https://datatracker.ietf.org/doc/html/rfc2177
148//! [RFC 2193]: https://datatracker.ietf.org/doc/html/rfc2193
149//! [RFC 2221]: https://datatracker.ietf.org/doc/html/rfc2221
150//! [RFC 3501]: https://datatracker.ietf.org/doc/html/rfc3501
151//! [RFC 3691]: https://datatracker.ietf.org/doc/html/rfc3691
152//! [RFC 4959]: https://datatracker.ietf.org/doc/html/rfc4959
153//! [RFC 4978]: https://datatracker.ietf.org/doc/html/rfc4978
154//! [RFC 5161]: https://datatracker.ietf.org/doc/html/rfc5161
155//! [RFC 6851]: https://datatracker.ietf.org/doc/html/rfc6851
156//! [RFC 7162]: https://datatracker.ietf.org/doc/html/rfc7162
157//! [RFC 7888]: https://datatracker.ietf.org/doc/html/rfc7888
158//! [RFC 9208]: https://datatracker.ietf.org/doc/html/rfc9208
159
160#![forbid(unsafe_code)]
161#![deny(missing_debug_implementations)]
162// TODO(#313)
163// #![deny(missing_docs)]
164#![cfg_attr(docsrs, feature(doc_cfg))]
165
166#[cfg(feature = "arbitrary")]
167mod arbitrary;
168pub mod auth;
169pub mod body;
170pub mod command;
171pub mod core;
172pub mod datetime;
173pub mod envelope;
174pub mod error;
175pub mod extensions;
176pub mod fetch;
177pub mod flag;
178pub mod mailbox;
179pub mod response;
180pub mod search;
181pub mod secret;
182pub mod sequence;
183pub mod state;
184pub mod status;
185pub mod utils;
186
187#[cfg(feature = "bounded-static")]
188pub use bounded_static;