commons_net/
lib.rs

1//! # FTP Protocol
2//! ftp is an FTP client written in Rust.
3//!
4//! ### Usage
5//!
6//! Here is a basic usage example:
7//!
8//! ```rust,no_run
9//! use commons_net::ftp::ftp_client::FtpClient;
10//! use commons_net::ftp::types::FtpError;
11//! async fn test_ftp(addr: &str, user: &str, pass: &str) -> Result<(), FtpError> {
12//! let mut ftp_client = FtpClient::connect((addr, 21)).await?;
13//!     ftp_client.login(user, pass).await?;
14//!     println!("current dir: {}", ftp_client.pwd().await?);
15//!
16//!     // ftp_stream.make_directory("test_data").await?;
17//!
18//!     ftp_client.cwd("RCX/03021008-RCX/A00").await?;
19//!
20//!     println!("current dir: {}", ftp_client.pwd().await?);
21//!     // An easy way to retrieve a File
22//!     let cursor = ftp_client.simple_retr("03021008-RCX_A00(0000).txt").await?;
23//!     let vec = cursor.into_inner();
24//!     let text = str::from_utf8(&vec).unwrap();
25//!     println!("got data: {}", text);
26//!     ftp_client.logout().await?;
27//!     Ok(())
28//! }
29//!
30//! fn main() {
31//!     let future = test_ftp("192.168.32.204", "ftpuser", "ftp123");
32//!
33//!     tokio::runtime::Builder::new_current_thread()
34//!         .enable_all()
35//!         .build()
36//!         .unwrap()
37//!         .block_on(future)
38//!         .unwrap();
39//!
40//!     println!("test successful")
41//! }
42//! ```
43//!
44//!
45//! ### FTPS
46//!
47//! The client supports FTPS on demand. To enable it the client should be
48//! compiled with feature `openssl` enabled what requires
49//! [openssl](https://crates.io/crates/openssl) dependency.
50//!
51//! The client uses explicit mode for connecting FTPS what means you should
52//! connect the server as usually and then switch to the secure mode (TLS is used).
53//! For better security it's the good practice to switch to the secure mode
54//! before authentication.
55//!
56//! ### FTPS Usage
57//!
58//! ```rust,no_run
59//! use std::convert::TryFrom;
60//! use std::path::Path;
61//! use tokio_rustls::rustls::{ClientConfig, RootCertStore, ServerName};
62//! use commons_net::ftp::ftp_client::FtpClient;
63//!
64//! async {
65//!   let ftp_client = FtpClient::connect("192.168.32.204:21").await.unwrap();
66//!
67//!   let mut root_store = RootCertStore::empty();
68//!   // root_store.add_pem_file(...);
69//!   let conf = ClientConfig::builder().with_safe_defaults().with_root_certificates(root_store).with_no_client_auth();
70//!   let domain = ServerName::try_from("www.cert-domain.com").expect("invalid DNS name");
71//!
72//!   // Switch to the secure mode
73//!   let mut ftp_client = ftp_client.into_secure(conf, domain).await.unwrap();
74//!   ftp_client.login("anonymous", "anonymous").await.unwrap();
75//!   // Do other secret stuff
76//!   // Switch back to the insecure mode (if required)
77//!   let mut ftp_client = ftp_client.into_insecure().await.unwrap();
78//!   // Do all public stuff
79//!   let _ = ftp_client.quit().await;
80//! };
81//! ```
82//!
83//!
84//! # SMTP Protocol
85//! asap...
86
87pub mod ftp;
88pub mod smtp;
89
90pub trait StringExt {
91    fn substring(&self, start_index: usize, end_index: usize) -> &str;
92}
93
94impl StringExt for str {
95    fn substring(&self, start_index: usize, end_index: usize) -> &str {
96        if end_index <= start_index {
97            return "";
98        }
99
100        let mut indices = self.char_indices();
101
102        let obtain_index = |(index, _char)| index;
103        let str_len = self.len();
104
105        unsafe {
106            self.slice_unchecked(
107                indices.nth(start_index).map_or(str_len, &obtain_index),
108                indices
109                    .nth(end_index - start_index - 1)
110                    .map_or(str_len, &obtain_index),
111            )
112        }
113    }
114}