repair mailbox table, add unix stream support

This commit is contained in:
Clément DOUIN
2026-03-03 20:16:05 +01:00
parent 297f5773aa
commit ffa26594a4
4 changed files with 492 additions and 116 deletions
Generated
+283 -1
View File
@@ -83,7 +83,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "367fd0ad87307588d087544707bc5fbf4805ded96c7db922b70d368fa1cb5702"
dependencies = [
"concolor",
"unicode-width",
"unicode-width 0.1.14",
"yansi",
]
@@ -132,6 +132,9 @@ name = "bitflags"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
dependencies = [
"serde_core",
]
[[package]]
name = "bounded-static"
@@ -280,6 +283,17 @@ dependencies = [
"memchr",
]
[[package]]
name = "comfy-table"
version = "7.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "958c5d6ecf1f214b4c2bbbbf6ab9523a864bd136dcf71a7e8904799acfe1ad47"
dependencies = [
"crossterm 0.29.0",
"unicode-segmentation",
"unicode-width 0.2.2",
]
[[package]]
name = "concolor"
version = "0.0.11"
@@ -313,6 +327,46 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "crossterm"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
dependencies = [
"bitflags 2.11.0",
"crossterm_winapi",
"libc",
"mio",
"parking_lot",
"serde",
"signal-hook",
"signal-hook-mio",
"winapi",
]
[[package]]
name = "crossterm"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
dependencies = [
"bitflags 2.11.0",
"crossterm_winapi",
"document-features",
"parking_lot",
"rustix",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
dependencies = [
"winapi",
]
[[package]]
name = "dirs"
version = "6.0.0"
@@ -345,6 +399,15 @@ dependencies = [
"syn",
]
[[package]]
name = "document-features"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61"
dependencies = [
"litrs",
]
[[package]]
name = "dunce"
version = "1.0.5"
@@ -521,6 +584,8 @@ dependencies = [
"anyhow",
"ariadne",
"clap",
"comfy-table",
"crossterm 0.27.0",
"io-imap",
"io-process",
"io-stream",
@@ -533,6 +598,7 @@ dependencies = [
"serde",
"serde_json",
"shellexpand",
"uds_windows",
"url",
"uuid",
]
@@ -864,6 +930,21 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
[[package]]
name = "litrs"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.29"
@@ -876,12 +957,33 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "memoffset"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
dependencies = [
"autocfg",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "mio"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.48.0",
]
[[package]]
name = "native-tls"
version = "0.2.18"
@@ -980,6 +1082,29 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "parking_lot"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-link",
]
[[package]]
name = "percent-encoding"
version = "2.3.2"
@@ -1116,6 +1241,15 @@ dependencies = [
"getrandom 0.2.17",
]
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags 2.11.0",
]
[[package]]
name = "redox_users"
version = "0.5.2"
@@ -1288,6 +1422,12 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "secrecy"
version = "0.10.3"
@@ -1403,6 +1543,37 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-mio"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc"
dependencies = [
"libc",
"mio",
"signal-hook",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
dependencies = [
"errno",
"libc",
]
[[package]]
name = "smallvec"
version = "1.15.1"
@@ -1563,18 +1734,41 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
[[package]]
name = "uds_windows"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9"
dependencies = [
"memoffset",
"tempfile",
"winapi",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "unicode-width"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "unicode-xid"
version = "0.2.6"
@@ -1751,6 +1945,22 @@ dependencies = [
"rustls-pki-types",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.11"
@@ -1760,6 +1970,12 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-link"
version = "0.2.1"
@@ -1775,6 +1991,15 @@ dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
@@ -1817,6 +2042,21 @@ dependencies = [
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
@@ -1856,6 +2096,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
@@ -1874,6 +2120,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
@@ -1892,6 +2144,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
@@ -1922,6 +2180,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
@@ -1940,6 +2204,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
@@ -1958,6 +2228,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
@@ -1976,6 +2252,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
+5 -4
View File
@@ -39,10 +39,8 @@ pimalaya-toolbox = { version = "0.0.4", default-features = false, features = ["b
anyhow = "1"
ariadne = { version = "0.2", features = ["auto-color"] }
clap = { version = "4.4", features = ["derive", "env", "wrap_help"] }
# email-lib = { version = "0.27", default-features = false, features = ["tokio-rustls", "derive", "thread"] }
# mml-lib = { version = "1", default-features = false, features = ["compiler", "interpreter", "derive"] }
# once_cell = "1.16"
# open = "5.3"
comfy-table = "7"
crossterm = { version = "0.27", features = ["serde"] }
io-imap = { version = "0.0.1", default-features = false, optional = true }
io-process = { version = "0.0.2", default-features = false }
io-stream = { version = "0.0.2", default-features = false, features = ["std"] }
@@ -58,6 +56,9 @@ shellexpand = "3.1"
url = { version = "2.2", features = ["serde"] }
uuid = { version = "1.19", features = ["v4"] }
[target.'cfg(windows)'.dependencies]
uds_windows = "1"
[patch.crates-io]
pimalaya-toolbox.path = "../toolbox"
io-imap.path = "../imap"
+170 -88
View File
@@ -1,8 +1,13 @@
use std::{fmt, ops::Deref};
use anyhow::{bail, Result};
use clap::Parser;
use comfy_table::{presets, Cell, ContentArrangement, Row, Table};
use crossterm::style::Color;
use io_imap::coroutines::list::*;
use io_stream::runtimes::std::handle;
use pimalaya_toolbox::terminal::printer::Printer;
use serde::{Serialize, Serializer};
use crate::{config::ImapConfig, imap::stream};
@@ -23,7 +28,7 @@ pub struct ListMailboxesCommand {
}
impl ListMailboxesCommand {
pub fn execute(self, _printer: &mut impl Printer, config: ImapConfig) -> Result<()> {
pub fn execute(self, printer: &mut impl Printer, config: ImapConfig) -> Result<()> {
let (context, mut stream) = stream::connect(config)?;
let mut arg = None;
@@ -37,109 +42,186 @@ impl ListMailboxesCommand {
}
};
println!("mailboxes: {mailboxes:#?}");
let table = MailboxesTable::from(mailboxes);
// TODO: list mailboxs
// let mailboxs = Mailboxs::from(backend.list_mailboxs().await?);
// let table = MailboxsTable::from(mailboxs)
// .with_some_width(self.table_max_width)
// .with_some_preset(toml_account_config.mailbox_list_table_preset())
// .with_some_name_color(toml_account_config.mailbox_list_table_name_color())
// .with_some_desc_color(toml_account_config.mailbox_list_table_desc_color());
// printer.out(table)?;
printer.out(table)?;
Ok(())
}
}
// #[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
// #[serde(rename_all = "kebab-case")]
// pub struct ListMailboxesTableConfig {
// pub preset: Option<String>,
// pub name_color: Option<Color>,
// pub desc_color: Option<Color>,
// }
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
#[serde(rename_all = "kebab-case")]
pub struct ListMailboxesTableConfig {
pub preset: Option<String>,
pub name_color: Option<Color>,
pub desc_color: Option<Color>,
}
// impl ListMailboxesTableConfig {
// pub fn preset(&self) -> &str {
// self.preset.as_deref().unwrap_or(presets::ASCII_MARKDOWN)
// }
impl ListMailboxesTableConfig {
pub fn preset(&self) -> &str {
self.preset.as_deref().unwrap_or(presets::ASCII_MARKDOWN)
}
// pub fn name_color(&self) -> comfy_table::Color {
// map_color(self.name_color.unwrap_or(Color::Blue))
// }
pub fn name_color(&self) -> comfy_table::Color {
map_color(self.name_color.unwrap_or(Color::Blue))
}
// pub fn desc_color(&self) -> comfy_table::Color {
// map_color(self.desc_color.unwrap_or(Color::Green))
// }
// }
pub fn desc_color(&self) -> comfy_table::Color {
map_color(self.desc_color.unwrap_or(Color::Green))
}
}
// pub struct MailboxesTable {
// mailboxes: Vec<Mailbox<'static>>,
// width: Option<u16>,
// config: ListMailboxesTableConfig,
// }
#[derive(Clone, Debug, Serialize)]
pub struct Mailbox {
pub name: String,
pub delimiter: String,
pub attributes: Vec<String>,
}
// impl MailboxesTable {
// pub fn with_some_width(mut self, width: Option<u16>) -> Self {
// self.width = width;
// self
// }
#[derive(Clone, Debug, Default, Serialize)]
pub struct Mailboxes(Vec<Mailbox>);
// pub fn with_some_preset(mut self, preset: Option<String>) -> Self {
// self.config.preset = preset;
// self
// }
impl<T: IntoIterator<Item = Mailbox>> From<T> for Mailboxes {
fn from(mboxes: T) -> Self {
Self(mboxes.into_iter().collect())
}
}
// pub fn with_some_name_color(mut self, color: Option<Color>) -> Self {
// self.config.name_color = color;
// self
// }
impl Deref for Mailboxes {
type Target = Vec<Mailbox>;
// pub fn with_some_desc_color(mut self, color: Option<Color>) -> Self {
// self.config.desc_color = color;
// self
// }
// }
fn deref(&self) -> &Self::Target {
&self.0
}
}
// impl From<Mailboxes> for MailboxesTable {
// fn from(mailboxes: Mailboxes) -> Self {
// Self {
// mailboxes,
// width: None,
// config: Default::default(),
// }
// }
// }
pub struct MailboxesTable {
mailboxes: Mailboxes,
width: Option<u16>,
config: ListMailboxesTableConfig,
}
// impl fmt::Display for MailboxesTable {
// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// let mut table = Table::new();
impl MailboxesTable {
pub fn with_some_width(mut self, width: Option<u16>) -> Self {
self.width = width;
self
}
// table
// .load_preset(self.config.preset())
// .set_content_arrangement(ContentArrangement::DynamicFullWidth)
// .set_header(Row::from([Cell::new("NAME"), Cell::new("DESC")]))
// .add_rows(
// self.mailboxes
// .iter()
// .map(|mailbox| mailbox.to_row(&self.config)),
// );
pub fn with_some_preset(mut self, preset: Option<String>) -> Self {
self.config.preset = preset;
self
}
// if let Some(width) = self.width {
// table.set_width(width);
// }
pub fn with_some_name_color(mut self, color: Option<Color>) -> Self {
self.config.name_color = color;
self
}
// writeln!(f)?;
// write!(f, "{table}")?;
// writeln!(f)?;
// Ok(())
// }
// }
pub fn with_some_desc_color(mut self, color: Option<Color>) -> Self {
self.config.desc_color = color;
self
}
}
// impl Serialize for MailboxesTable {
// fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
// self.mailboxes.serialize(serializer)
// }
// }
impl
From<
Vec<(
io_imap::types::mailbox::Mailbox<'static>,
Option<io_imap::types::core::QuotedChar>,
Vec<io_imap::types::flag::FlagNameAttribute<'static>>,
)>,
> for MailboxesTable
{
fn from(
mailboxes: Vec<(
io_imap::types::mailbox::Mailbox<'static>,
Option<io_imap::types::core::QuotedChar>,
Vec<io_imap::types::flag::FlagNameAttribute<'static>>,
)>,
) -> Self {
Self {
mailboxes: mailboxes
.into_iter()
.map(|(mbox, delim, attrs)| Mailbox {
name: match mbox {
io_imap::types::mailbox::Mailbox::Inbox => "Inbox".into(),
io_imap::types::mailbox::Mailbox::Other(mbox) => {
String::from_utf8_lossy(mbox.inner().as_ref()).to_string()
}
},
delimiter: match delim {
Some(delim) => delim.inner().to_string(),
None => String::new(),
},
attributes: attrs.into_iter().map(|attr| attr.to_string()).collect(),
})
.into(),
width: None,
config: Default::default(),
}
}
}
impl fmt::Display for MailboxesTable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut table = Table::new();
table
.load_preset(self.config.preset())
.set_content_arrangement(ContentArrangement::DynamicFullWidth)
.set_header(Row::from([
Cell::new("NAME"),
Cell::new("DELIMITER"),
Cell::new("ATTRIBUTES"),
]))
.add_rows(self.mailboxes.iter().map(|mbox| {
let mut row = Row::new();
row.max_height(1);
row.add_cell(Cell::new(&mbox.name).fg(self.config.name_color()));
row.add_cell(Cell::new(&mbox.delimiter).fg(self.config.desc_color()));
row.add_cell(Cell::new(&mbox.attributes.join(", ")).fg(self.config.desc_color()));
row
}));
if let Some(width) = self.width {
table.set_width(width);
}
writeln!(f)?;
write!(f, "{table}")?;
writeln!(f)?;
Ok(())
}
}
impl Serialize for MailboxesTable {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.mailboxes.serialize(serializer)
}
}
fn map_color(color: Color) -> comfy_table::Color {
match color {
Color::Reset => comfy_table::Color::Reset,
Color::Black => comfy_table::Color::Black,
Color::DarkGrey => comfy_table::Color::DarkGrey,
Color::Red => comfy_table::Color::Red,
Color::DarkRed => comfy_table::Color::DarkRed,
Color::Green => comfy_table::Color::Green,
Color::DarkGreen => comfy_table::Color::DarkGreen,
Color::Yellow => comfy_table::Color::Yellow,
Color::DarkYellow => comfy_table::Color::DarkYellow,
Color::Blue => comfy_table::Color::Blue,
Color::DarkBlue => comfy_table::Color::DarkBlue,
Color::Magenta => comfy_table::Color::Magenta,
Color::DarkMagenta => comfy_table::Color::DarkMagenta,
Color::Cyan => comfy_table::Color::Cyan,
Color::DarkCyan => comfy_table::Color::DarkCyan,
Color::White => comfy_table::Color::White,
Color::Grey => comfy_table::Color::Grey,
Color::Rgb { r, g, b } => comfy_table::Color::Rgb { r, g, b },
Color::AnsiValue(n) => comfy_table::Color::AnsiValue(n),
}
}
+34 -23
View File
@@ -1,9 +1,10 @@
#[cfg(unix)]
use std::os::unix::net::UnixStream;
use std::{
fs,
io::{self, Read, Write},
net::TcpStream,
sync::Arc,
time::Duration,
};
use anyhow::{bail, Result};
@@ -28,33 +29,25 @@ use rustls::{
};
#[cfg(any(feature = "rustls-aws", feature = "rustls-ring"))]
use rustls_platform_verifier::{ConfigVerifierExt, Verifier};
#[cfg(windows)]
use uds_windows::UnixStream;
use crate::config::{ImapConfig, RustlsCryptoConfig, SaslMechanismConfig, TlsProviderConfig};
pub enum Stream {
Plain(TcpStream),
Tcp(TcpStream),
Unix(UnixStream),
#[cfg(any(feature = "rustls-aws", feature = "rustls-ring"))]
Rustls(StreamOwned<ClientConnection, TcpStream>),
#[cfg(feature = "native-tls")]
NativeTls(native_tls::TlsStream<TcpStream>),
}
impl Stream {
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
match self {
Self::Plain(s) => s.set_read_timeout(dur),
#[cfg(any(feature = "rustls-aws", feature = "rustls-ring"))]
Self::Rustls(s) => s.get_ref().set_read_timeout(dur),
#[cfg(feature = "native-tls")]
Self::NativeTls(s) => s.get_ref().set_read_timeout(dur),
}
}
}
impl Read for Stream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
Self::Plain(s) => s.read(buf),
Self::Tcp(s) => s.read(buf),
Self::Unix(s) => s.read(buf),
#[cfg(any(feature = "rustls-aws", feature = "rustls-ring"))]
Self::Rustls(s) => s.read(buf),
#[cfg(feature = "native-tls")]
@@ -66,7 +59,8 @@ impl Read for Stream {
impl Write for Stream {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self {
Self::Plain(s) => s.write(buf),
Self::Tcp(s) => s.write(buf),
Self::Unix(s) => s.write(buf),
#[cfg(any(feature = "rustls-aws", feature = "rustls-ring"))]
Self::Rustls(s) => s.write(buf),
#[cfg(feature = "native-tls")]
@@ -76,7 +70,8 @@ impl Write for Stream {
fn flush(&mut self) -> io::Result<()> {
match self {
Self::Plain(s) => s.flush(),
Self::Tcp(s) => s.flush(),
Self::Unix(s) => s.flush(),
#[cfg(any(feature = "rustls-aws", feature = "rustls-ring"))]
Self::Rustls(s) => s.flush(),
#[cfg(feature = "native-tls")]
@@ -109,11 +104,11 @@ pub fn connect(mut config: ImapConfig) -> Result<(ImapContext, Stream)> {
}
}
(context, Stream::Plain(stream))
(context, Stream::Tcp(stream))
}
scheme if scheme.eq_ignore_ascii_case("imaps") => {
let port = config.url.port().unwrap_or(993);
let mut tcp = TcpStream::connect((host, port))?;
let mut stream = TcpStream::connect((host, port))?;
if config.starttls {
let mut coroutine = ImapStartTls::new(context);
@@ -121,7 +116,7 @@ pub fn connect(mut config: ImapConfig) -> Result<(ImapContext, Stream)> {
loop {
match coroutine.resume(arg.take()) {
ImapStartTlsResult::Io(io) => arg = Some(handle(&mut tcp, io)?),
ImapStartTlsResult::Io(io) => arg = Some(handle(&mut stream, io)?),
ImapStartTlsResult::Ok { context: c } => break context = c,
ImapStartTlsResult::Err { err, .. } => Err(err)?,
}
@@ -226,7 +221,7 @@ pub fn connect(mut config: ImapConfig) -> Result<(ImapContext, Stream)> {
let server_name = host.to_string().try_into()?;
let conn = ClientConnection::new(Arc::new(config), server_name)?;
Stream::Rustls(StreamOwned::new(conn, tcp))
Stream::Rustls(StreamOwned::new(conn, stream))
}
#[cfg(feature = "native-tls")]
TlsProviderConfig::NativeTls => {
@@ -240,7 +235,7 @@ pub fn connect(mut config: ImapConfig) -> Result<(ImapContext, Stream)> {
}
let connector = builder.build()?;
Stream::NativeTls(connector.connect(host, tcp)?)
Stream::NativeTls(connector.connect(host, stream)?)
}
#[allow(unreachable_patterns)]
_ => unreachable!(),
@@ -277,7 +272,23 @@ pub fn connect(mut config: ImapConfig) -> Result<(ImapContext, Stream)> {
(context, stream)
}
scheme if scheme.eq_ignore_ascii_case("unix") => {
todo!()
let sock_path = config.url.path();
let mut stream = UnixStream::connect(&sock_path)?;
let mut coroutine = GetImapGreetingWithCapability::new(context);
let mut arg = None;
loop {
match coroutine.resume(arg.take()) {
GetImapGreetingWithCapabilityResult::Io(io) => {
arg = Some(handle(&mut stream, io)?)
}
GetImapGreetingWithCapabilityResult::Ok { context: c } => break context = c,
GetImapGreetingWithCapabilityResult::Err { err, .. } => Err(err)?,
}
}
(context, Stream::Unix(stream))
}
scheme => {
bail!("Unknown scheme {scheme}, expected imap, imaps or unix");