ftp_rs/lib.rs
1//! ftp is an FTP client written in Rust.
2//!
3//! ### Usage
4//!
5//! Here is a basic usage example:
6//!
7//! ```rust,no_run
8//! use ftp_rs::FtpClient;
9//! async {
10//! let mut ftp_client = FtpClient::connect("192.168.32.204:21").await.unwrap_or_else(|err|
11//! panic!("{}", err)
12//! );
13//! let _ = ftp_client.quit();
14//! };
15//! ```
16//!
17//! ### FTPS
18//!
19//! The client supports FTPS on demand. To enable it the client should be
20//! compiled with feature `openssl` enabled what requires
21//! [openssl](https://crates.io/crates/openssl) dependency.
22//!
23//! The client uses explicit mode for connecting FTPS what means you should
24//! connect the server as usually and then switch to the secure mode (TLS is used).
25//! For better security it's the good practice to switch to the secure mode
26//! before authentication.
27//!
28//! ### FTPS Usage
29//!
30//! ```rust,no_run
31//! use std::convert::TryFrom;
32//! use std::path::Path;
33//! use ftp_rs::FtpClient;
34//! use tokio_rustls::rustls::{ClientConfig, RootCertStore, ServerName};
35//!
36//! async {
37//! let ftp_client = FtpClient::connect("192.168.32.204:21").await.unwrap();
38//!
39//! let mut root_store = RootCertStore::empty();
40//! // root_store.add_pem_file(...);
41//! let conf = ClientConfig::builder().with_safe_defaults().with_root_certificates(root_store).with_no_client_auth();
42//! let domain = ServerName::try_from("www.cert-domain.com").expect("invalid DNS name");
43//!
44//! // Switch to the secure mode
45//! let mut ftp_client = ftp_client.into_secure(conf, domain).await.unwrap();
46//! ftp_client.login("anonymous", "anonymous").await.unwrap();
47//! // Do other secret stuff
48//! // Switch back to the insecure mode (if required)
49//! let mut ftp_client = ftp_client.into_insecure().await.unwrap();
50//! // Do all public stuff
51//! let _ = ftp_client.quit().await;
52//! };
53//! ```
54//!
55
56mod connection;
57mod ftp_client;
58pub mod ftp_reply;
59pub mod types;
60pub mod cmd;
61
62pub use self::connection::Connection;
63pub use self::ftp_client::FtpClient;
64pub use self::types::FtpError;
65
66pub const REPLY_CODE_LEN: usize = 3;
67
68pub const MODES: &'static str = "AEILNTCFRPSBC";
69
70pub trait StringExt {
71 fn substring(&self, start_index: usize, end_index: usize) -> &str;
72}
73
74impl StringExt for str {
75 fn substring(&self, start_index: usize, end_index: usize) -> &str {
76 if end_index <= start_index {
77 return "";
78 }
79
80 let mut indices = self.char_indices();
81
82 let obtain_index = |(index, _char)| index;
83 let str_len = self.len();
84
85 unsafe {
86 self.slice_unchecked(
87 indices.nth(start_index).map_or(str_len, &obtain_index),
88 indices
89 .nth(end_index - start_index - 1)
90 .map_or(str_len, &obtain_index),
91 )
92 }
93 }
94}