Skip to content

Commit beebfb5

Browse files
committed
Update top-level documentation and fix broken references
1 parent ba338e3 commit beebfb5

File tree

6 files changed

+90
-115
lines changed

6 files changed

+90
-115
lines changed

README.md

+1-46
Original file line numberDiff line numberDiff line change
@@ -61,52 +61,7 @@ The documentation within this crate borrows heavily from the various RFCs, but s
6161
considered a complete reference. If anything is unclear, follow the links to the RFCs embedded
6262
in the documentation for the various types and methods and read the raw text there!
6363

64-
Below is a basic client example. See the `examples/` directory for more.
65-
66-
```rust
67-
use async_std::prelude::*;
68-
use async_imap::error::Result;
69-
70-
async fn fetch_inbox_top() -> Result<Option<String>> {
71-
let domain = "imap.example.com";
72-
let tls = async_native_tls::TlsConnector::new();
73-
74-
// we pass in the domain twice to check that the server's TLS
75-
// certificate is valid for the domain we're connecting to.
76-
let client = async_imap::connect((domain, 993), domain, tls).await?;
77-
78-
// the client we have here is unauthenticated.
79-
// to do anything useful with the e-mails, we need to log in
80-
let mut imap_session = client
81-
.login("[email protected]", "password")
82-
.await
83-
.map_err(|e| e.0)?;
84-
85-
// we want to fetch the first email in the INBOX mailbox
86-
imap_session.select("INBOX").await?;
87-
88-
// fetch message number 1 in this mailbox, along with its RFC822 field.
89-
// RFC 822 dictates the format of the body of e-mails
90-
let messages_stream = imap_session.fetch("1", "RFC822").await?;
91-
let messages: Vec<_> = messages_stream.collect::<Result<_>>().await?;
92-
let message = if let Some(m) = messages.first() {
93-
m
94-
} else {
95-
return Ok(None);
96-
};
97-
98-
// extract the message's body
99-
let body = message.body().expect("message did not have a body!");
100-
let body = std::str::from_utf8(body)
101-
.expect("message was not valid utf-8")
102-
.to_string();
103-
104-
// be nice to the server and log out
105-
imap_session.logout().await?;
106-
107-
Ok(Some(body))
108-
}
109-
```
64+
See the `examples/` directory for examples.
11065

11166
## Running the test suite
11267

src/authenticator.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
/// This trait allows for pluggable authentication schemes. It is used by `Client::authenticate` to
1+
/// This trait allows for pluggable authentication schemes. It is used by [`Client::authenticate`] to
22
/// [authenticate using SASL](https://tools.ietf.org/html/rfc3501#section-6.2.2).
3+
///
4+
/// [`Client::authenticate`]: crate::Client::authenticate
35
pub trait Authenticator {
46
/// The type of the response to the challenge. This will usually be a `Vec<u8>` or `String`.
57
type Response: AsRef<[u8]>;

src/client.rs

+6-8
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ pub struct Client<T: Read + Write + Unpin + fmt::Debug> {
8181
/// The underlying primitives type. Both `Client`(unauthenticated) and `Session`(after succesful
8282
/// login) use a `Connection` internally for the TCP stream primitives.
8383
#[derive(Debug)]
84-
#[doc(hidden)]
8584
pub struct Connection<T: Read + Write + Unpin + fmt::Debug> {
8685
pub(crate) stream: ImapStream<T>,
8786

@@ -393,7 +392,7 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
393392
}
394393
}
395394

396-
/// Selects a mailbox
395+
/// Selects a mailbox.
397396
///
398397
/// The `SELECT` command selects a mailbox so that messages in the mailbox can be accessed.
399398
/// Note that earlier versions of this protocol only required the FLAGS, EXISTS, and RECENT
@@ -407,10 +406,9 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
407406
///
408407
/// Note that the server *is* allowed to unilaterally send things to the client for messages in
409408
/// a selected mailbox whose status has changed. See the note on [unilateral server responses
410-
/// in RFC 3501](https://tools.ietf.org/html/rfc3501#section-7). This means that if you use
411-
/// [`Connection::run_command_and_read_response`], you *may* see additional untagged `RECENT`,
412-
/// `EXISTS`, `FETCH`, and `EXPUNGE` responses. You can get them from the
413-
/// `unsolicited_responses` channel of the [`Session`](struct.Session.html).
409+
/// in RFC 3501](https://tools.ietf.org/html/rfc3501#section-7). This means that if run commands,
410+
/// you *may* see additional untagged `RECENT`, `EXISTS`, `FETCH`, and `EXPUNGE` responses.
411+
/// You can get them from the `unsolicited_responses` channel of the [`Session`](struct.Session.html).
414412
pub async fn select<S: AsRef<str>>(&mut self, mailbox_name: S) -> Result<Mailbox> {
415413
// TODO: also note READ/WRITE vs READ-only mode!
416414
let id = self
@@ -426,8 +424,8 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
426424
Ok(mbox)
427425
}
428426

429-
/// Selects a mailbox with `(CONDSTORE)` parameter as defined in [RFC
430-
/// 7162](https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1.8).
427+
/// Selects a mailbox with `(CONDSTORE)` parameter as defined in
428+
/// [RFC 7162](https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1.8).
431429
pub async fn select_condstore<S: AsRef<str>>(&mut self, mailbox_name: S) -> Result<Mailbox> {
432430
let id = self
433431
.run_command(&format!(

src/extensions/idle.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use crate::types::ResponseData;
3434
/// Note that the server MAY consider a client inactive if it has an IDLE command running, and if
3535
/// such a server has an inactivity timeout it MAY log the client off implicitly at the end of its
3636
/// timeout period. Because of that, clients using IDLE are advised to terminate the IDLE and
37-
/// re-issue it at least every 29 minutes to avoid being logged off. [`Handle::wait_keepalive`]
37+
/// re-issue it at least every 29 minutes to avoid being logged off. [`Handle::wait`]
3838
/// does this. This still allows a client to receive immediate mailbox updates even though it need
3939
/// only "poll" at half hour intervals.
4040
///
@@ -55,7 +55,7 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Stream for Handle<T> {
5555
}
5656
}
5757

58-
/// A stream of server responses after sending `IDLE`. Created using [Handle::stream].
58+
/// A stream of server responses after sending `IDLE`.
5959
#[derive(Debug)]
6060
#[must_use = "futures do nothing unless polled"]
6161
pub struct IdleStream<'a, St> {
@@ -112,8 +112,8 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Handle<T> {
112112
Handle { session, id: None }
113113
}
114114

115-
/// Start listening to the server side resonses.
116-
/// Must be called after [Handle::init].
115+
/// Start listening to the server side responses.
116+
/// Must be called after [`Handle::init`].
117117
pub fn wait(
118118
&mut self,
119119
) -> (

src/imap_stream.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,13 @@ impl Buffer {
161161

162162
/// Indicate how many new bytes were written into the buffer.
163163
///
164-
/// When new bytes are written into the slice returned by [tail_as_slice] this method
164+
/// When new bytes are written into the slice returned by [`free_as_mut_slice`] this method
165165
/// should be called to extend the used portion of the buffer to include the new data.
166166
///
167167
/// You can not write past the end of the buffer, so extending more then there is free
168168
/// space marks the entire buffer as used.
169+
///
170+
/// [`free_as_mut_slice`]: Self::free_as_mut_slice
169171
// aka advance()?
170172
fn extend_used(&mut self, num_bytes: usize) {
171173
self.offset += num_bytes;
@@ -189,9 +191,12 @@ impl Buffer {
189191
/// Grows the buffer, ensuring there are free bytes in the tail.
190192
///
191193
/// The specified number of bytes is only a minimum. The buffer could grow by more as
192-
/// it will always grow in multiples of [BLOCK_SIZE].
194+
/// it will always grow in multiples of [`BLOCK_SIZE`].
195+
///
196+
/// If the size would be larger than [`MAX_CAPACITY`] an error is returned.
193197
///
194-
/// If the size would be larger than [MAX_CAPACITY] an error is returned.
198+
/// [`BLOCK_SIZE`]: Self::BLOCK_SIZE
199+
/// [`MAX_CAPACITY`]: Self::MAX_CAPACITY
195200
// TODO: This bypasses the byte-pool block re-use. That's bad.
196201
fn grow(&mut self, num_bytes: usize) -> io::Result<()> {
197202
let min_size = self.block.size() + num_bytes;
@@ -212,16 +217,19 @@ impl Buffer {
212217

213218
/// Return the block backing the buffer.
214219
///
215-
/// Next you *must* either return this block using [return_block] or call
216-
/// [reset_with_data].
220+
/// Next you *must* either return this block using [`return_block`] or call
221+
/// [`reset_with_data`].
222+
///
223+
/// [`return_block`]: Self::return_block
224+
/// [`reset_with_data`]: Self::reset_with_data
217225
// TODO: Enforce this with typestate.
218226
fn take_block(&mut self) -> Block<'static> {
219227
std::mem::replace(&mut self.block, POOL.alloc(Self::BLOCK_SIZE))
220228
}
221229

222230
/// Reset the buffer to be a new allocation with given data copied in.
223231
///
224-
/// This allows the previously returned block from [get_block] to be used in and owned
232+
/// This allows the previously returned block from `get_block` to be used in and owned
225233
/// by the [ResponseData].
226234
///
227235
/// This does not do any bounds checking to see if the new buffer would exceed the

src/lib.rs

+62-50
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,78 @@
1-
//! This crate lets you connect to and interact with servers that implement the IMAP protocol
2-
//! ([RFC 3501](https://tools.ietf.org/html/rfc3501) and various extensions).
3-
//! After authenticating with the server, IMAP lets you list, fetch, and search for e-mails,
1+
//! # Async IMAP
2+
//!
3+
//! This crate lets you connect to and interact with servers
4+
//! that implement the IMAP protocol ([RFC 3501](https://tools.ietf.org/html/rfc3501) and extensions).
5+
//! After authenticating with the server,
6+
//! IMAP lets you list, fetch, and search for e-mails,
47
//! as well as monitor mailboxes for changes.
58
//!
6-
//! To connect, use the [`connect`] function. This gives you an unauthenticated [`Client`]. You can
7-
//! then use [`Client::login`] or [`Client::authenticate`] to perform username/password or
8-
//! challenge/response authentication respectively. This in turn gives you an authenticated
9-
//! [`Session`], which lets you access the mailboxes at the server.
9+
//! ## Connecting
1010
//!
11-
//! The documentation within this crate borrows heavily from the various RFCs,
12-
//! but should not be considered a complete reference.
13-
//! If anything is unclear,
14-
//! follow the links to the RFCs embedded in the documentation
15-
//! for the various types and methods and read the raw text there!
11+
//! Connect to the server, for example using TLS connection on port 993
12+
//! or plain TCP connection on port 143 if you plan to use STARTTLS.
13+
//! can be used.
14+
//! Pass the stream to [`Client::new()`].
15+
//! This gives you an unauthenticated [`Client`].
1616
//!
17-
//! Below is a basic client example. See the `examples/` directory for more.
17+
//! Then read the server greeting:
18+
//! ```ignore
19+
//! let _greeting = client
20+
//! .read_response().await?
21+
//! .expect("unexpected end of stream, expected greeting");
22+
//! ```
1823
//!
19-
//! ```no_run
20-
//! use futures::prelude::*;
21-
//! use async_imap::error::Result;
24+
//! ## STARTTLS
2225
//!
23-
//! #[cfg(feature = "async-native-tls")]
24-
//! async fn fetch_inbox_top() -> Result<Option<String>> {
25-
//! let domain = "imap.example.com";
26-
//! let tls = async_native_tls::TlsConnector::new();
26+
//! If you connected on a non-TLS port, upgrade the connection using STARTTLS:
27+
//! ```ignore
28+
//! client.run_command_and_check_ok("STARTTLS", None).await?;
29+
//! let stream = client.into_inner();
30+
//! ```
31+
//! Convert this stream into a TLS stream using a library
32+
//! such as [`async-native-tls`](https://crates.io/crates/async-native-tls)
33+
//! or [Rustls](`https://crates.io/crates/rustls`).
34+
//! Once you have a TLS stream, wrap it back into a [`Client`]:
35+
//! ```ignore
36+
//! let client = Client::new(tls_stream);
37+
//! ```
38+
//! Note that there is no server greeting after STARTTLS.
2739
//!
28-
//! // we pass in the domain twice to check that the server's TLS
29-
//! // certificate is valid for the domain we're connecting to.
30-
//! let client = async_imap::connect((domain, 993), domain, tls).await?;
40+
//! ## Authentication and session usage
3141
//!
32-
//! // the client we have here is unauthenticated.
33-
//! // to do anything useful with the e-mails, we need to log in
34-
//! let mut imap_session = client
35-
//! .login("[email protected]", "password")
36-
//! .await
37-
//! .map_err(|e| e.0)?;
42+
//! Once you have an established connection,
43+
//! authenticate using [`Client::login`] or [`Client::authenticate`]
44+
//! to perform username/password or challenge/response authentication respectively.
45+
//! This in turn gives you an authenticated
46+
//! [`Session`], which lets you access the mailboxes at the server.
47+
//! For example:
48+
//! ```ignore
49+
//! let mut session = client
50+
//! .login("[email protected]", "password").await
51+
//! .map_err(|(err, _client)| err)?;
52+
//! session.select("INBOX").await?;
3853
//!
39-
//! // we want to fetch the first email in the INBOX mailbox
40-
//! imap_session.select("INBOX").await?;
54+
//! // Fetch message number 1 in this mailbox, along with its RFC 822 field.
55+
//! // RFC 822 dictates the format of the body of e-mails.
56+
//! let messages_stream = imap_session.fetch("1", "RFC822").await?;
57+
//! let messages: Vec<_> = messages_stream.try_collect().await?;
58+
//! let message = messages.first().expect("found no messages in the INBOX");
4159
//!
42-
//! // fetch message number 1 in this mailbox, along with its RFC822 field.
43-
//! // RFC 822 dictates the format of the body of e-mails
44-
//! let messages_stream = imap_session.fetch("1", "RFC822").await?;
45-
//! let messages: Vec<_> = messages_stream.try_collect().await?;
46-
//! let message = if let Some(m) = messages.first() {
47-
//! m
48-
//! } else {
49-
//! return Ok(None);
50-
//! };
60+
//! // Extract the message body.
61+
//! let body = message.body().expect("message did not have a body!");
62+
//! let body = std::str::from_utf8(body)
63+
//! .expect("message was not valid utf-8")
64+
//! .to_string();
5165
//!
52-
//! // extract the message's body
53-
//! let body = message.body().expect("message did not have a body!");
54-
//! let body = std::str::from_utf8(body)
55-
//! .expect("message was not valid utf-8")
56-
//! .to_string();
66+
//! session.logout().await?;
67+
//! ```
5768
//!
58-
//! // be nice to the server and log out
59-
//! imap_session.logout().await?;
69+
//! The documentation within this crate borrows heavily from the various RFCs,
70+
//! but should not be considered a complete reference.
71+
//! If anything is unclear,
72+
//! follow the links to the RFCs embedded in the documentation
73+
//! for the various types and methods and read the raw text there!
6074
//!
61-
//! Ok(Some(body))
62-
//! }
63-
//! ```
75+
//! See the `examples/` directory for usage examples.
6476
#![warn(missing_docs)]
6577
#![deny(rust_2018_idioms, unsafe_code)]
6678

0 commit comments

Comments
 (0)