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};