mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-24 20:10:23 +00:00
refactor builders and sync
This commit is contained in:
parent
ab1e8b7e45
commit
c254f64569
14 changed files with 405 additions and 364 deletions
65
Cargo.lock
generated
65
Cargo.lock
generated
|
@ -1009,6 +1009,21 @@ dependencies = [
|
||||||
"new_debug_unreachable",
|
"new_debug_unreachable",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures"
|
||||||
|
version = "0.3.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-io",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.25"
|
version = "0.3.25"
|
||||||
|
@ -1016,6 +1031,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
|
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1024,6 +1040,17 @@ version = "0.3.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
|
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-executor"
|
||||||
|
version = "0.3.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-io"
|
name = "futures-io"
|
||||||
version = "0.3.25"
|
version = "0.3.25"
|
||||||
|
@ -1074,6 +1101,7 @@ version = "0.3.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
|
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-macro",
|
"futures-macro",
|
||||||
|
@ -1187,7 +1215,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "himalaya"
|
name = "himalaya"
|
||||||
version = "0.8.1"
|
version = "0.8.1-beta"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"atty",
|
"atty",
|
||||||
|
@ -1217,6 +1245,7 @@ dependencies = [
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
"terminal_size",
|
"terminal_size",
|
||||||
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
"toml_edit",
|
"toml_edit",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
|
@ -2170,15 +2199,16 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pimalaya-email"
|
name = "pimalaya-email"
|
||||||
version = "0.9.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2e85cdc815af8f35c67941eaac74dc2e6a8d01c3ed498b2d36eaaf9bc8a517e6"
|
checksum = "6b881982050e29d8f9141a57f0be3f87471394462a2f1695471d5a81f44b4b3a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"advisory-lock",
|
"advisory-lock",
|
||||||
"ammonia",
|
"ammonia",
|
||||||
"chrono",
|
"chrono",
|
||||||
"convert_case",
|
"convert_case",
|
||||||
"dirs",
|
"dirs",
|
||||||
|
"futures",
|
||||||
"html-escape",
|
"html-escape",
|
||||||
"imap",
|
"imap",
|
||||||
"imap-proto",
|
"imap-proto",
|
||||||
|
@ -2214,9 +2244,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pimalaya-email-tpl"
|
name = "pimalaya-email-tpl"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e25da44b70885d9636ddcb89181a2f0155acff3816697ec7af07a5f6f17cdc0e"
|
checksum = "f640b701926112e28b025cea9c9d50a2bfe329862eeb4acbf2d62edeb53fb19b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chumsky 0.9.0",
|
"chumsky 0.9.0",
|
||||||
"log",
|
"log",
|
||||||
|
@ -2231,9 +2261,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pimalaya-keyring"
|
name = "pimalaya-keyring"
|
||||||
version = "0.0.1"
|
version = "0.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae5fed5fff1897b4964a5e8efbcd5e41e4492fe7947f827745fe9a14a555fe94"
|
checksum = "cef72189d57c09a3c682769e7c99d44772bb1164173e77e77cef837ba8dda1b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"keyring",
|
"keyring",
|
||||||
"log",
|
"log",
|
||||||
|
@ -2242,9 +2272,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pimalaya-oauth2"
|
name = "pimalaya-oauth2"
|
||||||
version = "0.0.2"
|
version = "0.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c9bec4262b62b6b14ffa244727e3d86d69e608e664e162e2c73332bed3b3f8a1"
|
checksum = "6a28b3da9e56304f14bd46f769bfae52de32bd3fc2795946079e66838a178ce8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"oauth2",
|
"oauth2",
|
||||||
|
@ -2265,13 +2295,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pimalaya-secret"
|
name = "pimalaya-secret"
|
||||||
version = "0.0.1"
|
version = "0.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b585f585653ac7f957a608d8cdffd81be6561c2ad92fa82a1e72ed62a1bb31e0"
|
checksum = "9338dc84e5ec9fc25f3a36d82ed68ffe4888ad728ca1aa42228e27648ddff01f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"pimalaya-keyring",
|
"pimalaya-keyring",
|
||||||
"pimalaya-oauth2",
|
|
||||||
"pimalaya-process",
|
"pimalaya-process",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
@ -3153,9 +3182,21 @@ dependencies = [
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2",
|
||||||
|
"tokio-macros",
|
||||||
"windows-sys 0.42.0",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-macros"
|
||||||
|
version = "1.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.104",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-rustls"
|
name = "tokio-rustls"
|
||||||
version = "0.23.4"
|
version = "0.23.4"
|
||||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "himalaya"
|
name = "himalaya"
|
||||||
description = "CLI to manage your emails."
|
description = "CLI to manage your emails."
|
||||||
version = "0.8.1"
|
version = "0.8.1-beta"
|
||||||
authors = ["soywod <clement.douin@posteo.net>"]
|
authors = ["soywod <clement.douin@posteo.net>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
@ -44,16 +44,17 @@ indicatif = "0.17"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
md5 = "0.7.0"
|
md5 = "0.7.0"
|
||||||
once_cell = "1.16.0"
|
once_cell = "1.16.0"
|
||||||
pimalaya-email = "=0.9.0"
|
pimalaya-email = { version = "=0.10.0", default-features = false }
|
||||||
pimalaya-keyring = "=0.0.1"
|
pimalaya-keyring = "=0.0.4"
|
||||||
pimalaya-oauth2 = "=0.0.2"
|
pimalaya-oauth2 = "=0.0.3"
|
||||||
pimalaya-process = "=0.0.2"
|
pimalaya-process = "=0.0.2"
|
||||||
pimalaya-secret = "=0.0.1"
|
pimalaya-secret = "=0.0.2"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
shellexpand = "2.1"
|
shellexpand = "2.1"
|
||||||
termcolor = "1.1"
|
termcolor = "1.1"
|
||||||
terminal_size = "0.1"
|
terminal_size = "0.1"
|
||||||
|
tokio = { version = "1.23", default-features = false, features = ["macros"] }
|
||||||
toml = "0.7.4"
|
toml = "0.7.4"
|
||||||
toml_edit = "0.19.8"
|
toml_edit = "0.19.8"
|
||||||
unicode-width = "0.1"
|
unicode-width = "0.1"
|
||||||
|
|
24
flake.lock
24
flake.lock
|
@ -8,11 +8,11 @@
|
||||||
"rust-analyzer-src": "rust-analyzer-src"
|
"rust-analyzer-src": "rust-analyzer-src"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1682835640,
|
"lastModified": 1686032467,
|
||||||
"narHash": "sha256-rAYEOd4nZFLjDlrF9KNlcopPKNVtr1svSXcEValVRMY=",
|
"narHash": "sha256-KUCS237H0G1QGx5ehhEmh5yKtcDGCxvVXVtz8xEDAKE=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "fenix",
|
"repo": "fenix",
|
||||||
"rev": "006b429d3c493f4c5b1743a94f71ad961c7693ab",
|
"rev": "1a3e0f661119a7435099b118912d65bdbbf3bb11",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -42,11 +42,11 @@
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1681202837,
|
"lastModified": 1685518550,
|
||||||
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -97,11 +97,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1682817260,
|
"lastModified": 1685883127,
|
||||||
"narHash": "sha256-kFMXzKNj4d/0Iqbm5l57rHSLyUeyCLMuvlROZIuuhvk=",
|
"narHash": "sha256-zPDaPNrAtBnO24rNqjHLINHsqTdRbgWy1c/TL3EdwlM=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "db1e4eeb0f9a9028bcb920e00abbc1409dd3ef36",
|
"rev": "d4a9ff82fc18723219b60c66fb2ccb0734c460eb",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -124,11 +124,11 @@
|
||||||
"rust-analyzer-src": {
|
"rust-analyzer-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1682792082,
|
"lastModified": 1685984106,
|
||||||
"narHash": "sha256-1nuP2rqipsdB8IJ3N5ws3FQm4dX3mKIueIrCUSu1bWw=",
|
"narHash": "sha256-dOEuU1AuASOWdXT/SbVpD8uX7JjiW3lCp08SbviHuww=",
|
||||||
"owner": "rust-lang",
|
"owner": "rust-lang",
|
||||||
"repo": "rust-analyzer",
|
"repo": "rust-analyzer",
|
||||||
"rev": "7bcb4c2ef23e151a639ff918fbb8ab9d521eabb9",
|
"rev": "d42d55feaafa71e14521bbfe6e7011fbb41980f0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
21
src/cache/id_mapper.rs
vendored
21
src/cache/id_mapper.rs
vendored
|
@ -16,10 +16,7 @@ pub enum IdMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IdMapper {
|
impl IdMapper {
|
||||||
fn find_closest_db_path<D>(dir: D) -> PathBuf
|
pub fn find_closest_db_path(dir: impl AsRef<Path>) -> PathBuf {
|
||||||
where
|
|
||||||
D: AsRef<Path>,
|
|
||||||
{
|
|
||||||
let mut db_path = dir.as_ref().join(ID_MAPPER_DB_FILE_NAME);
|
let mut db_path = dir.as_ref().join(ID_MAPPER_DB_FILE_NAME);
|
||||||
let mut db_parent_dir = dir.as_ref().parent();
|
let mut db_parent_dir = dir.as_ref().parent();
|
||||||
|
|
||||||
|
@ -40,20 +37,20 @@ impl IdMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(backend: &dyn Backend, account: &str, folder: &str) -> Result<Self> {
|
pub fn new(backend: &dyn Backend, account: &str, folder: &str) -> Result<Self> {
|
||||||
let mut db_path = PathBuf::default();
|
|
||||||
|
|
||||||
if let Some(backend) = backend.as_any().downcast_ref::<MaildirBackend>() {
|
|
||||||
db_path = Self::find_closest_db_path(&backend.path());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
if backend.as_any().is::<ImapBackend>() {
|
if backend.as_any().is::<ImapBackend>() {
|
||||||
return Ok(Self::Dummy);
|
return Ok(IdMapper::Dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut db_path = PathBuf::new();
|
||||||
|
|
||||||
|
if let Some(backend) = backend.as_any().downcast_ref::<MaildirBackend>() {
|
||||||
|
db_path = Self::find_closest_db_path(backend.path())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "notmuch-backend")]
|
#[cfg(feature = "notmuch-backend")]
|
||||||
if let Some(backend) = backend.as_any().downcast_ref::<NotmuchBackend>() {
|
if let Some(backend) = backend.as_any().downcast_ref::<NotmuchBackend>() {
|
||||||
db_path = Self::find_closest_db_path(&backend.path());
|
db_path = Self::find_closest_db_path(backend.path())
|
||||||
}
|
}
|
||||||
|
|
||||||
let digest = md5::compute(account.to_string() + folder);
|
let digest = md5::compute(account.to_string() + folder);
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
#[cfg(feature = "imap-backend")]
|
|
||||||
use pimalaya_email::ImapConfig;
|
|
||||||
#[cfg(feature = "notmuch-backend")]
|
#[cfg(feature = "notmuch-backend")]
|
||||||
use pimalaya_email::NotmuchConfig;
|
use pimalaya_email::NotmuchConfig;
|
||||||
use pimalaya_email::{
|
use pimalaya_email::{
|
||||||
folder::sync::Strategy as SyncFoldersStrategy, BackendConfig, EmailHooks, EmailTextPlainFormat,
|
BackendConfig, EmailHooks, EmailTextPlainFormat, FolderSyncStrategy, MaildirConfig,
|
||||||
ImapAuthConfig, MaildirConfig, OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig,
|
OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig, SenderConfig, SendmailConfig,
|
||||||
SenderConfig, SendmailConfig, SmtpAuthConfig, SmtpConfig,
|
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "imap-backend")]
|
||||||
|
use pimalaya_email::{ImapAuthConfig, ImapConfig};
|
||||||
|
#[cfg(feature = "smtp-sender")]
|
||||||
|
use pimalaya_email::{SmtpAuthConfig, SmtpConfig};
|
||||||
use pimalaya_keyring::Entry;
|
use pimalaya_keyring::Entry;
|
||||||
use pimalaya_process::{Cmd, Pipeline, SingleCmd};
|
use pimalaya_process::{Cmd, Pipeline, SingleCmd};
|
||||||
use pimalaya_secret::Secret;
|
use pimalaya_secret::Secret;
|
||||||
|
@ -74,14 +75,16 @@ impl From<OptionCmd> for Option<Cmd> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "Secret", rename_all = "kebab-case")]
|
#[serde(remote = "Secret", rename_all = "kebab-case")]
|
||||||
pub enum SecretDef {
|
pub enum SecretDef {
|
||||||
Raw(String),
|
Raw(String),
|
||||||
#[serde(with = "CmdDef")]
|
#[serde(with = "CmdDef")]
|
||||||
Cmd(Cmd),
|
Cmd(Cmd),
|
||||||
#[serde(with = "EntryDef")]
|
#[serde(with = "EntryDef", rename = "keyring")]
|
||||||
Keyring(Entry),
|
KeyringEntry(Entry),
|
||||||
|
#[default]
|
||||||
|
Undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
@ -134,6 +137,7 @@ pub struct ImapConfigDef {
|
||||||
pub watch_cmds: Option<Vec<String>>,
|
pub watch_cmds: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "imap-backend")]
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "ImapAuthConfig", tag = "imap-auth")]
|
#[serde(remote = "ImapAuthConfig", tag = "imap-auth")]
|
||||||
pub enum ImapAuthConfigDef {
|
pub enum ImapAuthConfigDef {
|
||||||
|
@ -150,7 +154,7 @@ pub struct ImapPasswdConfigDef {
|
||||||
rename = "imap-passwd",
|
rename = "imap-passwd",
|
||||||
with = "SecretDef",
|
with = "SecretDef",
|
||||||
default,
|
default,
|
||||||
skip_serializing_if = "Secret::is_undefined_entry"
|
skip_serializing_if = "Secret::is_undefined"
|
||||||
)]
|
)]
|
||||||
pub passwd: Secret,
|
pub passwd: Secret,
|
||||||
}
|
}
|
||||||
|
@ -166,7 +170,7 @@ pub struct ImapOAuth2ConfigDef {
|
||||||
rename = "imap-oauth2-client-secret",
|
rename = "imap-oauth2-client-secret",
|
||||||
with = "SecretDef",
|
with = "SecretDef",
|
||||||
default,
|
default,
|
||||||
skip_serializing_if = "Secret::is_undefined_entry"
|
skip_serializing_if = "Secret::is_undefined"
|
||||||
)]
|
)]
|
||||||
pub client_secret: Secret,
|
pub client_secret: Secret,
|
||||||
#[serde(rename = "imap-oauth2-auth-url")]
|
#[serde(rename = "imap-oauth2-auth-url")]
|
||||||
|
@ -177,20 +181,30 @@ pub struct ImapOAuth2ConfigDef {
|
||||||
rename = "imap-oauth2-access-token",
|
rename = "imap-oauth2-access-token",
|
||||||
with = "SecretDef",
|
with = "SecretDef",
|
||||||
default,
|
default,
|
||||||
skip_serializing_if = "Secret::is_undefined_entry"
|
skip_serializing_if = "Secret::is_undefined"
|
||||||
)]
|
)]
|
||||||
pub access_token: Secret,
|
pub access_token: Secret,
|
||||||
#[serde(
|
#[serde(
|
||||||
rename = "imap-oauth2-refresh-token",
|
rename = "imap-oauth2-refresh-token",
|
||||||
with = "SecretDef",
|
with = "SecretDef",
|
||||||
default,
|
default,
|
||||||
skip_serializing_if = "Secret::is_undefined_entry"
|
skip_serializing_if = "Secret::is_undefined"
|
||||||
)]
|
)]
|
||||||
pub refresh_token: Secret,
|
pub refresh_token: Secret,
|
||||||
#[serde(flatten, with = "ImapOAuth2ScopesDef")]
|
#[serde(flatten, with = "ImapOAuth2ScopesDef")]
|
||||||
pub scopes: OAuth2Scopes,
|
pub scopes: OAuth2Scopes,
|
||||||
#[serde(rename = "imap-oauth2-pkce", default)]
|
#[serde(rename = "imap-oauth2-pkce", default)]
|
||||||
pub pkce: bool,
|
pub pkce: bool,
|
||||||
|
#[serde(
|
||||||
|
rename = "imap-oauth2-redirect-host",
|
||||||
|
default = "OAuth2Config::default_redirect_host"
|
||||||
|
)]
|
||||||
|
pub redirect_host: String,
|
||||||
|
#[serde(
|
||||||
|
rename = "imap-oauth2-redirect-port",
|
||||||
|
default = "OAuth2Config::default_redirect_port"
|
||||||
|
)]
|
||||||
|
pub redirect_port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
@ -236,12 +250,14 @@ pub enum EmailTextPlainFormatDef {
|
||||||
pub enum SenderConfigDef {
|
pub enum SenderConfigDef {
|
||||||
#[default]
|
#[default]
|
||||||
None,
|
None,
|
||||||
|
#[cfg(feature = "smtp-sender")]
|
||||||
#[serde(with = "SmtpConfigDef")]
|
#[serde(with = "SmtpConfigDef")]
|
||||||
Smtp(SmtpConfig),
|
Smtp(SmtpConfig),
|
||||||
#[serde(with = "SendmailConfigDef")]
|
#[serde(with = "SendmailConfigDef")]
|
||||||
Sendmail(SendmailConfig),
|
Sendmail(SendmailConfig),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "smtp-sender")]
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "SmtpConfig")]
|
#[serde(remote = "SmtpConfig")]
|
||||||
struct SmtpConfigDef {
|
struct SmtpConfigDef {
|
||||||
|
@ -261,6 +277,7 @@ struct SmtpConfigDef {
|
||||||
pub auth: SmtpAuthConfig,
|
pub auth: SmtpAuthConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "smtp-sender")]
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "SmtpAuthConfig", tag = "smtp-auth")]
|
#[serde(remote = "SmtpAuthConfig", tag = "smtp-auth")]
|
||||||
pub enum SmtpAuthConfigDef {
|
pub enum SmtpAuthConfigDef {
|
||||||
|
@ -277,7 +294,7 @@ pub struct SmtpPasswdConfigDef {
|
||||||
rename = "smtp-passwd",
|
rename = "smtp-passwd",
|
||||||
with = "SecretDef",
|
with = "SecretDef",
|
||||||
default,
|
default,
|
||||||
skip_serializing_if = "Secret::is_undefined_entry"
|
skip_serializing_if = "Secret::is_undefined"
|
||||||
)]
|
)]
|
||||||
pub passwd: Secret,
|
pub passwd: Secret,
|
||||||
}
|
}
|
||||||
|
@ -293,7 +310,7 @@ pub struct SmtpOAuth2ConfigDef {
|
||||||
rename = "smtp-oauth2-client-secret",
|
rename = "smtp-oauth2-client-secret",
|
||||||
with = "SecretDef",
|
with = "SecretDef",
|
||||||
default,
|
default,
|
||||||
skip_serializing_if = "Secret::is_undefined_entry"
|
skip_serializing_if = "Secret::is_undefined"
|
||||||
)]
|
)]
|
||||||
pub client_secret: Secret,
|
pub client_secret: Secret,
|
||||||
#[serde(rename = "smtp-oauth2-auth-url")]
|
#[serde(rename = "smtp-oauth2-auth-url")]
|
||||||
|
@ -304,20 +321,30 @@ pub struct SmtpOAuth2ConfigDef {
|
||||||
rename = "smtp-oauth2-access-token",
|
rename = "smtp-oauth2-access-token",
|
||||||
with = "SecretDef",
|
with = "SecretDef",
|
||||||
default,
|
default,
|
||||||
skip_serializing_if = "Secret::is_undefined_entry"
|
skip_serializing_if = "Secret::is_undefined"
|
||||||
)]
|
)]
|
||||||
pub access_token: Secret,
|
pub access_token: Secret,
|
||||||
#[serde(
|
#[serde(
|
||||||
rename = "smtp-oauth2-refresh-token",
|
rename = "smtp-oauth2-refresh-token",
|
||||||
with = "SecretDef",
|
with = "SecretDef",
|
||||||
default,
|
default,
|
||||||
skip_serializing_if = "Secret::is_undefined_entry"
|
skip_serializing_if = "Secret::is_undefined"
|
||||||
)]
|
)]
|
||||||
pub refresh_token: Secret,
|
pub refresh_token: Secret,
|
||||||
#[serde(flatten, with = "SmtpOAuth2ScopesDef")]
|
#[serde(flatten, with = "SmtpOAuth2ScopesDef")]
|
||||||
pub scopes: OAuth2Scopes,
|
pub scopes: OAuth2Scopes,
|
||||||
#[serde(rename = "smtp-oauth2-pkce", default)]
|
#[serde(rename = "smtp-oauth2-pkce", default)]
|
||||||
pub pkce: bool,
|
pub pkce: bool,
|
||||||
|
#[serde(
|
||||||
|
rename = "imap-oauth2-redirect-host",
|
||||||
|
default = "OAuth2Config::default_redirect_host"
|
||||||
|
)]
|
||||||
|
pub redirect_host: String,
|
||||||
|
#[serde(
|
||||||
|
rename = "imap-oauth2-redirect-port",
|
||||||
|
default = "OAuth2Config::default_redirect_port"
|
||||||
|
)]
|
||||||
|
pub redirect_port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
@ -347,8 +374,8 @@ pub struct EmailHooksDef {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "SyncFoldersStrategy", rename_all = "kebab-case")]
|
#[serde(remote = "FolderSyncStrategy", rename_all = "kebab-case")]
|
||||||
pub enum SyncFoldersStrategyDef {
|
pub enum FolderSyncStrategyDef {
|
||||||
#[default]
|
#[default]
|
||||||
All,
|
All,
|
||||||
#[serde(alias = "only")]
|
#[serde(alias = "only")]
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||||
use log::info;
|
use log::info;
|
||||||
use pimalaya_email::folder::sync::Strategy as SyncFoldersStrategy;
|
use pimalaya_email::FolderSyncStrategy;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::{folder, ui::table};
|
use crate::{folder, ui::table};
|
||||||
|
@ -25,7 +25,7 @@ pub enum Cmd {
|
||||||
/// Represents the list accounts command.
|
/// Represents the list accounts command.
|
||||||
List(table::args::MaxTableWidth),
|
List(table::args::MaxTableWidth),
|
||||||
/// Represents the sync account command.
|
/// Represents the sync account command.
|
||||||
Sync(Option<SyncFoldersStrategy>, DryRun),
|
Sync(Option<FolderSyncStrategy>, DryRun),
|
||||||
/// Configure the current selected account.
|
/// Configure the current selected account.
|
||||||
Configure(Reset),
|
Configure(Reset),
|
||||||
}
|
}
|
||||||
|
@ -39,15 +39,15 @@ pub fn matches(m: &ArgMatches) -> Result<Option<Cmd>> {
|
||||||
let include = folder::args::parse_include_arg(m);
|
let include = folder::args::parse_include_arg(m);
|
||||||
let exclude = folder::args::parse_exclude_arg(m);
|
let exclude = folder::args::parse_exclude_arg(m);
|
||||||
let folders_strategy = if let Some(folder) = folder::args::parse_source_arg(m) {
|
let folders_strategy = if let Some(folder) = folder::args::parse_source_arg(m) {
|
||||||
Some(SyncFoldersStrategy::Include(HashSet::from_iter([
|
Some(FolderSyncStrategy::Include(HashSet::from_iter([
|
||||||
folder.to_owned()
|
folder.to_owned()
|
||||||
])))
|
])))
|
||||||
} else if !include.is_empty() {
|
} else if !include.is_empty() {
|
||||||
Some(SyncFoldersStrategy::Include(include.to_owned()))
|
Some(FolderSyncStrategy::Include(include.to_owned()))
|
||||||
} else if !exclude.is_empty() {
|
} else if !exclude.is_empty() {
|
||||||
Some(SyncFoldersStrategy::Exclude(exclude))
|
Some(FolderSyncStrategy::Exclude(exclude))
|
||||||
} else if folder::args::parse_all_arg(m) {
|
} else if folder::args::parse_all_arg(m) {
|
||||||
Some(SyncFoldersStrategy::All)
|
Some(FolderSyncStrategy::All)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,8 +8,8 @@ use pimalaya_email::ImapAuthConfig;
|
||||||
#[cfg(feature = "smtp-sender")]
|
#[cfg(feature = "smtp-sender")]
|
||||||
use pimalaya_email::SmtpAuthConfig;
|
use pimalaya_email::SmtpAuthConfig;
|
||||||
use pimalaya_email::{
|
use pimalaya_email::{
|
||||||
folder::sync::Strategy as SyncFoldersStrategy, AccountConfig, BackendConfig, EmailHooks,
|
AccountConfig, BackendConfig, EmailHooks, EmailTextPlainFormat, FolderSyncStrategy,
|
||||||
EmailTextPlainFormat, SenderConfig,
|
SenderConfig,
|
||||||
};
|
};
|
||||||
use pimalaya_process::Cmd;
|
use pimalaya_process::Cmd;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -76,10 +76,10 @@ pub struct DeserializedAccountConfig {
|
||||||
pub sync_dir: Option<PathBuf>,
|
pub sync_dir: Option<PathBuf>,
|
||||||
#[serde(
|
#[serde(
|
||||||
default,
|
default,
|
||||||
with = "SyncFoldersStrategyDef",
|
with = "FolderSyncStrategyDef",
|
||||||
skip_serializing_if = "SyncFoldersStrategy::is_default"
|
skip_serializing_if = "FolderSyncStrategy::is_default"
|
||||||
)]
|
)]
|
||||||
pub sync_folders_strategy: SyncFoldersStrategy,
|
pub sync_folders_strategy: FolderSyncStrategy,
|
||||||
|
|
||||||
#[serde(flatten, with = "BackendConfigDef")]
|
#[serde(flatten, with = "BackendConfigDef")]
|
||||||
pub backend: BackendConfig,
|
pub backend: BackendConfig,
|
||||||
|
@ -197,16 +197,16 @@ impl DeserializedAccountConfig {
|
||||||
if let BackendConfig::Imap(config) = &mut backend {
|
if let BackendConfig::Imap(config) = &mut backend {
|
||||||
match &mut config.auth {
|
match &mut config.auth {
|
||||||
ImapAuthConfig::Passwd(secret) => {
|
ImapAuthConfig::Passwd(secret) => {
|
||||||
secret.replace_undefined_entry_with(format!("{name}-imap-passwd"));
|
secret.set_keyring_entry_if_undefined(format!("{name}-imap-passwd"));
|
||||||
}
|
}
|
||||||
ImapAuthConfig::OAuth2(config) => {
|
ImapAuthConfig::OAuth2(config) => {
|
||||||
config.client_secret.replace_undefined_entry_with(format!(
|
config.client_secret.set_keyring_entry_if_undefined(format!(
|
||||||
"{name}-imap-oauth2-client-secret"
|
"{name}-imap-oauth2-client-secret"
|
||||||
));
|
));
|
||||||
config.access_token.replace_undefined_entry_with(format!(
|
config.access_token.set_keyring_entry_if_undefined(format!(
|
||||||
"{name}-imap-oauth2-access-token"
|
"{name}-imap-oauth2-access-token"
|
||||||
));
|
));
|
||||||
config.refresh_token.replace_undefined_entry_with(format!(
|
config.refresh_token.set_keyring_entry_if_undefined(format!(
|
||||||
"{name}-imap-oauth2-refresh-token"
|
"{name}-imap-oauth2-refresh-token"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -222,16 +222,16 @@ impl DeserializedAccountConfig {
|
||||||
if let SenderConfig::Smtp(config) = &mut sender {
|
if let SenderConfig::Smtp(config) = &mut sender {
|
||||||
match &mut config.auth {
|
match &mut config.auth {
|
||||||
SmtpAuthConfig::Passwd(secret) => {
|
SmtpAuthConfig::Passwd(secret) => {
|
||||||
secret.replace_undefined_entry_with(format!("{name}-smtp-passwd"));
|
secret.set_keyring_entry_if_undefined(format!("{name}-smtp-passwd"));
|
||||||
}
|
}
|
||||||
SmtpAuthConfig::OAuth2(config) => {
|
SmtpAuthConfig::OAuth2(config) => {
|
||||||
config.client_secret.replace_undefined_entry_with(format!(
|
config.client_secret.set_keyring_entry_if_undefined(format!(
|
||||||
"{name}-smtp-oauth2-client-secret"
|
"{name}-smtp-oauth2-client-secret"
|
||||||
));
|
));
|
||||||
config.access_token.replace_undefined_entry_with(format!(
|
config.access_token.set_keyring_entry_if_undefined(format!(
|
||||||
"{name}-smtp-oauth2-access-token"
|
"{name}-smtp-oauth2-access-token"
|
||||||
));
|
));
|
||||||
config.refresh_token.replace_undefined_entry_with(format!(
|
config.refresh_token.set_keyring_entry_if_undefined(format!(
|
||||||
"{name}-smtp-oauth2-refresh-token"
|
"{name}-smtp-oauth2-refresh-token"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,17 @@
|
||||||
//! This module gathers all account actions triggered by the CLI.
|
//! This module gathers all account actions triggered by the CLI.
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
use indicatif::{MultiProgress, ProgressBar, ProgressFinish, ProgressStyle};
|
||||||
use log::{info, trace, warn};
|
use log::{info, trace, warn};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
#[cfg(feature = "imap-backend")]
|
||||||
|
use pimalaya_email::ImapAuthConfig;
|
||||||
|
#[cfg(feature = "smtp-sender")]
|
||||||
|
use pimalaya_email::SmtpAuthConfig;
|
||||||
use pimalaya_email::{
|
use pimalaya_email::{
|
||||||
folder::sync::Strategy as SyncFoldersStrategy, AccountConfig, Backend, BackendConfig,
|
AccountConfig, BackendConfig, BackendSyncBuilder, BackendSyncProgressEvent, SenderConfig,
|
||||||
BackendSyncBuilder, BackendSyncProgressEvent, ImapAuthConfig, SenderConfig, SmtpAuthConfig,
|
|
||||||
};
|
};
|
||||||
|
use std::{collections::HashMap, sync::Mutex};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
config::{
|
||||||
|
@ -19,6 +24,21 @@ use crate::{
|
||||||
Accounts,
|
Accounts,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const MAIN_PROGRESS_STYLE: Lazy<ProgressStyle> = Lazy::new(|| {
|
||||||
|
ProgressStyle::with_template(" {spinner:.dim} {msg:.dim}\n {wide_bar:.cyan/blue} \n").unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
const SUB_PROGRESS_STYLE: Lazy<ProgressStyle> = Lazy::new(|| {
|
||||||
|
ProgressStyle::with_template(
|
||||||
|
" {prefix:.bold} — {wide_msg:.dim} \n {wide_bar:.black/black} {percent}% ",
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
const SUB_PROGRESS_DONE_STYLE: Lazy<ProgressStyle> = Lazy::new(|| {
|
||||||
|
ProgressStyle::with_template(" {prefix:.bold} \n {wide_bar:.green} {percent}% ").unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
/// Configure the current selected account
|
/// Configure the current selected account
|
||||||
pub fn configure(config: &AccountConfig, reset: bool) -> Result<()> {
|
pub fn configure(config: &AccountConfig, reset: bool) -> Result<()> {
|
||||||
info!("entering the configure account handler");
|
info!("entering the configure account handler");
|
||||||
|
@ -103,25 +123,16 @@ pub fn list<'a, P: Printer>(
|
||||||
|
|
||||||
/// Synchronizes the account defined using argument `-a|--account`. If
|
/// Synchronizes the account defined using argument `-a|--account`. If
|
||||||
/// no account given, synchronizes the default one.
|
/// no account given, synchronizes the default one.
|
||||||
pub fn sync<P: Printer>(
|
pub fn sync<'a, P: Printer>(
|
||||||
account_config: &AccountConfig,
|
|
||||||
printer: &mut P,
|
printer: &mut P,
|
||||||
backend: &dyn Backend,
|
sync_builder: BackendSyncBuilder<'a>,
|
||||||
folders_strategy: Option<SyncFoldersStrategy>,
|
|
||||||
dry_run: bool,
|
dry_run: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
info!("entering the sync accounts handler");
|
info!("entering the sync accounts handler");
|
||||||
trace!("dry run: {dry_run}");
|
trace!("dry run: {dry_run}");
|
||||||
trace!("folders strategy: {folders_strategy:#?}");
|
|
||||||
|
|
||||||
let mut sync_builder = BackendSyncBuilder::new(account_config);
|
|
||||||
|
|
||||||
if let Some(strategy) = folders_strategy {
|
|
||||||
sync_builder = sync_builder.folders_strategy(strategy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if dry_run {
|
if dry_run {
|
||||||
let report = sync_builder.dry_run(true).sync(backend)?;
|
let report = sync_builder.sync()?;
|
||||||
let mut hunks_count = report.folders_patch.len();
|
let mut hunks_count = report.folders_patch.len();
|
||||||
|
|
||||||
if !report.folders_patch.is_empty() {
|
if !report.folders_patch.is_empty() {
|
||||||
|
@ -142,98 +153,77 @@ pub fn sync<P: Printer>(
|
||||||
}
|
}
|
||||||
|
|
||||||
printer.print(format!(
|
printer.print(format!(
|
||||||
"Estimated patch length for account {} to be synchronized: {hunks_count}",
|
"Estimated patch length for account to be synchronized: {hunks_count}",
|
||||||
backend.name(),
|
|
||||||
))?;
|
))?;
|
||||||
} else if printer.is_json() {
|
} else if printer.is_json() {
|
||||||
sync_builder.sync(backend)?;
|
sync_builder.sync()?;
|
||||||
printer.print(format!(
|
printer.print("Account successfully synchronized!")?;
|
||||||
"Account {} successfully synchronized!",
|
|
||||||
backend.name()
|
|
||||||
))?;
|
|
||||||
} else {
|
} else {
|
||||||
let multi = MultiProgress::new();
|
let multi = MultiProgress::new();
|
||||||
let progress = multi.add(
|
let sub_progresses = Mutex::new(HashMap::new());
|
||||||
ProgressBar::new(0).with_style(
|
let main_progress = multi.add(
|
||||||
ProgressStyle::with_template(
|
ProgressBar::new(100)
|
||||||
" {spinner:.dim} {msg:.dim}\n {wide_bar:.cyan/blue} {pos}/{len} ",
|
.with_style(MAIN_PROGRESS_STYLE.clone())
|
||||||
)
|
.with_message("Synchronizing folders…"),
|
||||||
.unwrap(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Force the progress bar to show
|
||||||
|
main_progress.set_position(0);
|
||||||
|
|
||||||
let report = sync_builder
|
let report = sync_builder
|
||||||
.on_progress(|evt| {
|
.with_on_progress(move |evt| {
|
||||||
use BackendSyncProgressEvent::*;
|
use BackendSyncProgressEvent::*;
|
||||||
Ok(match evt {
|
Ok(match evt {
|
||||||
GetLocalCachedFolders => {
|
ApplyFolderPatches(..) => {
|
||||||
progress.set_length(4);
|
main_progress.inc(3);
|
||||||
progress.set_position(0);
|
|
||||||
progress.set_message("Getting local cached folders…");
|
|
||||||
}
|
}
|
||||||
GetLocalFolders => {
|
ApplyEnvelopePatches(patches) => {
|
||||||
progress.inc(1);
|
let mut envelopes_progresses = sub_progresses.lock().unwrap();
|
||||||
progress.set_message("Getting local maildir folders…");
|
let patches_len = patches.values().fold(0, |sum, patch| sum + patch.len());
|
||||||
|
main_progress.set_length((110 * patches_len / 100) as u64);
|
||||||
|
main_progress.set_position((5 * patches_len / 100) as u64);
|
||||||
|
main_progress.set_message("Synchronizing envelopes…");
|
||||||
|
|
||||||
|
for (folder, patch) in patches {
|
||||||
|
let progress = ProgressBar::new(patch.len() as u64)
|
||||||
|
.with_style(SUB_PROGRESS_STYLE.clone())
|
||||||
|
.with_prefix(folder.clone())
|
||||||
|
.with_finish(ProgressFinish::AndClear);
|
||||||
|
let progress = multi.add(progress);
|
||||||
|
envelopes_progresses.insert(folder, progress.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GetRemoteCachedFolders => {
|
ApplyEnvelopeHunk(hunk) => {
|
||||||
progress.inc(1);
|
main_progress.inc(1);
|
||||||
progress.set_message("Getting remote cached folders…");
|
let mut progresses = sub_progresses.lock().unwrap();
|
||||||
|
if let Some(progress) = progresses.get_mut(hunk.folder()) {
|
||||||
|
progress.inc(1);
|
||||||
|
if progress.position() == (progress.length().unwrap() - 1) {
|
||||||
|
progress.set_style(SUB_PROGRESS_DONE_STYLE.clone())
|
||||||
|
} else {
|
||||||
|
progress.set_message(format!("{hunk}…"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GetRemoteFolders => {
|
ApplyEnvelopeCachePatch(_patch) => {
|
||||||
progress.inc(1);
|
main_progress.set_length(100);
|
||||||
progress.set_message("Getting remote folders…");
|
main_progress.set_position(95);
|
||||||
|
main_progress.set_message("Saving cache database…");
|
||||||
}
|
}
|
||||||
BuildFoldersPatch => {
|
ExpungeFolders(folders) => {
|
||||||
progress.inc(1);
|
let mut progresses = sub_progresses.lock().unwrap();
|
||||||
progress.set_message("Building patch…");
|
for progress in progresses.values() {
|
||||||
}
|
progress.finish_and_clear()
|
||||||
ProcessFoldersPatch(n) => {
|
}
|
||||||
progress.set_length(n as u64);
|
progresses.clear();
|
||||||
progress.set_position(0);
|
|
||||||
progress.set_message("Processing patch…");
|
main_progress.set_position(100);
|
||||||
}
|
main_progress.set_message(format!("Expunging {} folders…", folders.len()));
|
||||||
ProcessFolderHunk(msg) => {
|
|
||||||
progress.inc(1);
|
|
||||||
progress.set_message(msg + "…");
|
|
||||||
}
|
|
||||||
StartEnvelopesSync(folder, n, len) => {
|
|
||||||
multi.println(format!("[{n:2}/{len}] {folder}")).unwrap();
|
|
||||||
progress.reset();
|
|
||||||
}
|
|
||||||
GetLocalCachedEnvelopes => {
|
|
||||||
progress.set_length(4);
|
|
||||||
progress.set_message("Getting local cached envelopes…");
|
|
||||||
}
|
|
||||||
GetLocalEnvelopes => {
|
|
||||||
progress.inc(1);
|
|
||||||
progress.set_message("Getting local maildir envelopes…");
|
|
||||||
}
|
|
||||||
GetRemoteCachedEnvelopes => {
|
|
||||||
progress.inc(1);
|
|
||||||
progress.set_message("Getting remote cached envelopes…");
|
|
||||||
}
|
|
||||||
GetRemoteEnvelopes => {
|
|
||||||
progress.inc(1);
|
|
||||||
progress.set_message("Getting remote envelopes…");
|
|
||||||
}
|
|
||||||
BuildEnvelopesPatch => {
|
|
||||||
progress.inc(1);
|
|
||||||
progress.set_message("Building patch…");
|
|
||||||
}
|
|
||||||
ProcessEnvelopesPatch(n) => {
|
|
||||||
progress.set_length(n as u64);
|
|
||||||
progress.set_position(0);
|
|
||||||
progress.set_message("Processing patch…");
|
|
||||||
}
|
|
||||||
ProcessEnvelopeHunk(msg) => {
|
|
||||||
progress.inc(1);
|
|
||||||
progress.set_message(msg + "…");
|
|
||||||
}
|
}
|
||||||
|
_ => (),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.sync(backend)?;
|
.sync()?;
|
||||||
|
|
||||||
progress.finish_and_clear();
|
|
||||||
|
|
||||||
let folders_patch_err = report
|
let folders_patch_err = report
|
||||||
.folders_patch
|
.folders_patch
|
||||||
|
@ -268,18 +258,14 @@ pub fn sync<P: Printer>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !report.envelopes_cache_patch.1.is_empty() {
|
if let Some(err) = report.envelopes_cache_patch.1 {
|
||||||
printer.print_log("")?;
|
printer.print_log("")?;
|
||||||
printer.print_log("Error occured while applying the envelopes cache patch:")?;
|
printer.print_log(format!(
|
||||||
for err in report.envelopes_cache_patch.1 {
|
"Error occured while applying the envelopes cache patch: {err}"
|
||||||
printer.print_log(format!(" - {err}"))?;
|
))?;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printer.print(format!(
|
printer.print("Account successfully synchronized!")?;
|
||||||
"Account {} successfully synchronized!",
|
|
||||||
backend.name()
|
|
||||||
))?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -2,13 +2,15 @@
|
||||||
//!
|
//!
|
||||||
//! This module gathers all IMAP handlers triggered by the CLI.
|
//! This module gathers all IMAP handlers triggered by the CLI.
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::Result;
|
||||||
use pimalaya_email::ImapBackend;
|
use pimalaya_email::ImapBackend;
|
||||||
|
|
||||||
pub fn notify(imap: &ImapBackend, folder: &str, keepalive: u64) -> Result<()> {
|
pub fn notify(imap: &mut ImapBackend, folder: &str, keepalive: u64) -> Result<()> {
|
||||||
imap.notify(keepalive, folder).context("cannot imap notify")
|
imap.notify(keepalive, folder)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn watch(imap: &ImapBackend, folder: &str, keepalive: u64) -> Result<()> {
|
pub fn watch(imap: &mut ImapBackend, folder: &str, keepalive: u64) -> Result<()> {
|
||||||
imap.watch(keepalive, folder).context("cannot imap watch")
|
imap.watch(keepalive, folder)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use pimalaya_email::{
|
||||||
BackendConfig, ImapAuthConfig, ImapConfig, OAuth2Config, OAuth2Method, OAuth2Scopes,
|
BackendConfig, ImapAuthConfig, ImapConfig, OAuth2Config, OAuth2Method, OAuth2Scopes,
|
||||||
PasswdConfig,
|
PasswdConfig,
|
||||||
};
|
};
|
||||||
use pimalaya_oauth2::AuthorizationCodeGrant;
|
use pimalaya_oauth2::{AuthorizationCodeGrant, Client};
|
||||||
use pimalaya_secret::Secret;
|
use pimalaya_secret::Secret;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -84,8 +84,8 @@ pub(crate) fn configure(account_name: &str, email: &str) -> Result<BackendConfig
|
||||||
|
|
||||||
let config = match secret {
|
let config = match secret {
|
||||||
Some(idx) if SECRETS[idx] == KEYRING => {
|
Some(idx) if SECRETS[idx] == KEYRING => {
|
||||||
Secret::new_keyring(format!("{account_name}-imap-passwd"))
|
Secret::new_keyring_entry(format!("{account_name}-imap-passwd"))
|
||||||
.set(prompt_passwd("IMAP password")?)?;
|
.set_keyring_entry_secret(prompt_passwd("IMAP password")?)?;
|
||||||
PasswdConfig::default()
|
PasswdConfig::default()
|
||||||
}
|
}
|
||||||
Some(idx) if SECRETS[idx] == RAW => PasswdConfig {
|
Some(idx) if SECRETS[idx] == RAW => PasswdConfig {
|
||||||
|
@ -125,8 +125,8 @@ pub(crate) fn configure(account_name: &str, email: &str) -> Result<BackendConfig
|
||||||
let client_secret: String = Password::with_theme(&*THEME)
|
let client_secret: String = Password::with_theme(&*THEME)
|
||||||
.with_prompt("IMAP OAuth 2.0 client secret")
|
.with_prompt("IMAP OAuth 2.0 client secret")
|
||||||
.interact()?;
|
.interact()?;
|
||||||
Secret::new_keyring(format!("{account_name}-imap-oauth2-client-secret"))
|
Secret::new_keyring_entry(format!("{account_name}-imap-oauth2-client-secret"))
|
||||||
.set(&client_secret)?;
|
.set_keyring_entry_secret(&client_secret)?;
|
||||||
|
|
||||||
config.auth_url = Input::with_theme(&*THEME)
|
config.auth_url = Input::with_theme(&*THEME)
|
||||||
.with_prompt("IMAP OAuth 2.0 authorization URL")
|
.with_prompt("IMAP OAuth 2.0 authorization URL")
|
||||||
|
@ -174,35 +174,42 @@ pub(crate) fn configure(account_name: &str, email: &str) -> Result<BackendConfig
|
||||||
|
|
||||||
wizard_log!("To complete your OAuth 2.0 setup, click on the following link:");
|
wizard_log!("To complete your OAuth 2.0 setup, click on the following link:");
|
||||||
|
|
||||||
let mut builder = AuthorizationCodeGrant::new(
|
let client = Client::new(
|
||||||
config.client_id.clone(),
|
config.client_id.clone(),
|
||||||
client_secret,
|
client_secret,
|
||||||
config.auth_url.clone(),
|
config.auth_url.clone(),
|
||||||
config.token_url.clone(),
|
config.token_url.clone(),
|
||||||
)?;
|
)?
|
||||||
|
.with_redirect_host(config.redirect_host.clone())
|
||||||
|
.with_redirect_port(config.redirect_port)
|
||||||
|
.build()?;
|
||||||
|
|
||||||
|
let mut auth_code_grant = AuthorizationCodeGrant::new()
|
||||||
|
.with_redirect_host(config.redirect_host.clone())
|
||||||
|
.with_redirect_port(config.redirect_port);
|
||||||
|
|
||||||
if config.pkce {
|
if config.pkce {
|
||||||
builder = builder.with_pkce();
|
auth_code_grant = auth_code_grant.with_pkce();
|
||||||
}
|
}
|
||||||
|
|
||||||
for scope in config.scopes.clone() {
|
for scope in config.scopes.clone() {
|
||||||
builder = builder.with_scope(scope);
|
auth_code_grant = auth_code_grant.with_scope(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
let client = builder.get_client()?;
|
let (redirect_url, csrf_token) = auth_code_grant.get_redirect_url(&client);
|
||||||
let (redirect_url, csrf_token) = builder.get_redirect_url(&client);
|
|
||||||
|
|
||||||
println!("{}", redirect_url.to_string());
|
println!("{}", redirect_url.to_string());
|
||||||
println!("");
|
println!("");
|
||||||
|
|
||||||
let (access_token, refresh_token) = builder.wait_for_redirection(client, csrf_token)?;
|
let (access_token, refresh_token) =
|
||||||
|
auth_code_grant.wait_for_redirection(&client, csrf_token)?;
|
||||||
|
|
||||||
Secret::new_keyring(format!("{account_name}-imap-oauth2-access-token"))
|
Secret::new_keyring_entry(format!("{account_name}-imap-oauth2-access-token"))
|
||||||
.set(access_token)?;
|
.set_keyring_entry_secret(access_token)?;
|
||||||
|
|
||||||
if let Some(refresh_token) = &refresh_token {
|
if let Some(refresh_token) = &refresh_token {
|
||||||
Secret::new_keyring(format!("{account_name}-imap-oauth2-refresh-token"))
|
Secret::new_keyring_entry(format!("{account_name}-imap-oauth2-refresh-token"))
|
||||||
.set(refresh_token)?;
|
.set_keyring_entry_secret(refresh_token)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImapAuthConfig::OAuth2(config)
|
ImapAuthConfig::OAuth2(config)
|
||||||
|
|
|
@ -135,10 +135,10 @@ mod tests {
|
||||||
fn name(&self) -> String {
|
fn name(&self) -> String {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
fn add_folder(&self, _: &str) -> backend::Result<()> {
|
fn add_folder(&mut self, _: &str) -> backend::Result<()> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
fn list_folders(&self) -> backend::Result<Folders> {
|
fn list_folders(&mut self) -> backend::Result<Folders> {
|
||||||
Ok(Folders::from_iter([
|
Ok(Folders::from_iter([
|
||||||
Folder {
|
Folder {
|
||||||
delim: "/".into(),
|
delim: "/".into(),
|
||||||
|
@ -152,23 +152,28 @@ mod tests {
|
||||||
},
|
},
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
fn expunge_folder(&self, _: &str) -> backend::Result<()> {
|
fn expunge_folder(&mut self, _: &str) -> backend::Result<()> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
fn purge_folder(&self, _: &str) -> backend::Result<()> {
|
fn purge_folder(&mut self, _: &str) -> backend::Result<()> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
fn delete_folder(&self, _: &str) -> backend::Result<()> {
|
fn delete_folder(&mut self, _: &str) -> backend::Result<()> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
fn get_envelope(&self, _: &str, _: &str) -> backend::Result<Envelope> {
|
fn get_envelope(&mut self, _: &str, _: &str) -> backend::Result<Envelope> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
fn list_envelopes(&self, _: &str, _: usize, _: usize) -> backend::Result<Envelopes> {
|
fn list_envelopes(
|
||||||
|
&mut self,
|
||||||
|
_: &str,
|
||||||
|
_: usize,
|
||||||
|
_: usize,
|
||||||
|
) -> backend::Result<Envelopes> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn search_envelopes(
|
fn search_envelopes(
|
||||||
&self,
|
&mut self,
|
||||||
_: &str,
|
_: &str,
|
||||||
_: &str,
|
_: &str,
|
||||||
_: &str,
|
_: &str,
|
||||||
|
@ -177,35 +182,38 @@ mod tests {
|
||||||
) -> backend::Result<Envelopes> {
|
) -> backend::Result<Envelopes> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn add_email(&self, _: &str, _: &[u8], _: &Flags) -> backend::Result<String> {
|
fn add_email(&mut self, _: &str, _: &[u8], _: &Flags) -> backend::Result<String> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn get_emails(&self, _: &str, _: Vec<&str>) -> backend::Result<Emails> {
|
fn get_emails(&mut self, _: &str, _: Vec<&str>) -> backend::Result<Emails> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn preview_emails(&self, _: &str, _: Vec<&str>) -> backend::Result<Emails> {
|
fn preview_emails(&mut self, _: &str, _: Vec<&str>) -> backend::Result<Emails> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn copy_emails(&self, _: &str, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
fn copy_emails(&mut self, _: &str, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn move_emails(&self, _: &str, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
fn move_emails(&mut self, _: &str, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn delete_emails(&self, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
fn delete_emails(&mut self, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn add_flags(&self, _: &str, _: Vec<&str>, _: &Flags) -> backend::Result<()> {
|
fn add_flags(&mut self, _: &str, _: Vec<&str>, _: &Flags) -> backend::Result<()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn set_flags(&self, _: &str, _: Vec<&str>, _: &Flags) -> backend::Result<()> {
|
fn set_flags(&mut self, _: &str, _: Vec<&str>, _: &Flags) -> backend::Result<()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn remove_flags(&self, _: &str, _: Vec<&str>, _: &Flags) -> backend::Result<()> {
|
fn remove_flags(&mut self, _: &str, _: Vec<&str>, _: &Flags) -> backend::Result<()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn as_any(&self) -> &(dyn Any) {
|
fn try_clone(&self) -> backend::Result<Box<dyn Backend>> {
|
||||||
self
|
unimplemented!()
|
||||||
|
}
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod sendmail;
|
pub mod sendmail;
|
||||||
|
#[cfg(feature = "smtp-sender")]
|
||||||
pub mod smtp;
|
pub mod smtp;
|
||||||
pub(crate) mod wizard;
|
pub(crate) mod wizard;
|
||||||
|
|
|
@ -4,7 +4,7 @@ use pimalaya_email::{
|
||||||
OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig, SenderConfig, SmtpAuthConfig,
|
OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig, SenderConfig, SmtpAuthConfig,
|
||||||
SmtpConfig,
|
SmtpConfig,
|
||||||
};
|
};
|
||||||
use pimalaya_oauth2::AuthorizationCodeGrant;
|
use pimalaya_oauth2::{AuthorizationCodeGrant, Client};
|
||||||
use pimalaya_secret::Secret;
|
use pimalaya_secret::Secret;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -84,8 +84,8 @@ pub(crate) fn configure(account_name: &str, email: &str) -> Result<SenderConfig>
|
||||||
|
|
||||||
let config = match secret {
|
let config = match secret {
|
||||||
Some(idx) if SECRETS[idx] == KEYRING => {
|
Some(idx) if SECRETS[idx] == KEYRING => {
|
||||||
Secret::new_keyring(format!("{account_name}-smtp-passwd"))
|
Secret::new_keyring_entry(format!("{account_name}-smtp-passwd"))
|
||||||
.set(prompt_passwd("SMTP password")?)?;
|
.set_keyring_entry_secret(prompt_passwd("SMTP password")?)?;
|
||||||
PasswdConfig::default()
|
PasswdConfig::default()
|
||||||
}
|
}
|
||||||
Some(idx) if SECRETS[idx] == RAW => PasswdConfig {
|
Some(idx) if SECRETS[idx] == RAW => PasswdConfig {
|
||||||
|
@ -125,8 +125,8 @@ pub(crate) fn configure(account_name: &str, email: &str) -> Result<SenderConfig>
|
||||||
let client_secret: String = Input::with_theme(&*THEME)
|
let client_secret: String = Input::with_theme(&*THEME)
|
||||||
.with_prompt("SMTP OAuth 2.0 client secret")
|
.with_prompt("SMTP OAuth 2.0 client secret")
|
||||||
.interact()?;
|
.interact()?;
|
||||||
Secret::new_keyring(format!("{account_name}-smtp-oauth2-client-secret"))
|
Secret::new_keyring_entry(format!("{account_name}-smtp-oauth2-client-secret"))
|
||||||
.set(&client_secret)?;
|
.set_keyring_entry_secret(&client_secret)?;
|
||||||
|
|
||||||
config.auth_url = Input::with_theme(&*THEME)
|
config.auth_url = Input::with_theme(&*THEME)
|
||||||
.with_prompt("SMTP OAuth 2.0 authorization URL")
|
.with_prompt("SMTP OAuth 2.0 authorization URL")
|
||||||
|
@ -174,35 +174,42 @@ pub(crate) fn configure(account_name: &str, email: &str) -> Result<SenderConfig>
|
||||||
|
|
||||||
wizard_log!("To complete your OAuth 2.0 setup, click on the following link:");
|
wizard_log!("To complete your OAuth 2.0 setup, click on the following link:");
|
||||||
|
|
||||||
let mut builder = AuthorizationCodeGrant::new(
|
let client = Client::new(
|
||||||
config.client_id.clone(),
|
config.client_id.clone(),
|
||||||
client_secret,
|
client_secret,
|
||||||
config.auth_url.clone(),
|
config.auth_url.clone(),
|
||||||
config.token_url.clone(),
|
config.token_url.clone(),
|
||||||
)?;
|
)?
|
||||||
|
.with_redirect_host(config.redirect_host.clone())
|
||||||
|
.with_redirect_port(config.redirect_port)
|
||||||
|
.build()?;
|
||||||
|
|
||||||
|
let mut auth_code_grant = AuthorizationCodeGrant::new()
|
||||||
|
.with_redirect_host(config.redirect_host.clone())
|
||||||
|
.with_redirect_port(config.redirect_port);
|
||||||
|
|
||||||
if config.pkce {
|
if config.pkce {
|
||||||
builder = builder.with_pkce();
|
auth_code_grant = auth_code_grant.with_pkce();
|
||||||
}
|
}
|
||||||
|
|
||||||
for scope in config.scopes.clone() {
|
for scope in config.scopes.clone() {
|
||||||
builder = builder.with_scope(scope);
|
auth_code_grant = auth_code_grant.with_scope(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
let client = builder.get_client()?;
|
let (redirect_url, csrf_token) = auth_code_grant.get_redirect_url(&client);
|
||||||
let (redirect_url, csrf_token) = builder.get_redirect_url(&client);
|
|
||||||
|
|
||||||
println!("{}", redirect_url.to_string());
|
println!("{}", redirect_url.to_string());
|
||||||
println!("");
|
println!("");
|
||||||
|
|
||||||
let (access_token, refresh_token) = builder.wait_for_redirection(client, csrf_token)?;
|
let (access_token, refresh_token) =
|
||||||
|
auth_code_grant.wait_for_redirection(&client, csrf_token)?;
|
||||||
|
|
||||||
Secret::new_keyring(format!("{account_name}-smtp-oauth2-access-token"))
|
Secret::new_keyring_entry(format!("{account_name}-smtp-oauth2-access-token"))
|
||||||
.set(access_token)?;
|
.set_keyring_entry_secret(access_token)?;
|
||||||
|
|
||||||
if let Some(refresh_token) = &refresh_token {
|
if let Some(refresh_token) = &refresh_token {
|
||||||
Secret::new_keyring(format!("{account_name}-smtp-oauth2-refresh-token"))
|
Secret::new_keyring_entry(format!("{account_name}-smtp-oauth2-refresh-token"))
|
||||||
.set(refresh_token)?;
|
.set_keyring_entry_secret(refresh_token)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SmtpAuthConfig::OAuth2(config)
|
SmtpAuthConfig::OAuth2(config)
|
||||||
|
|
224
src/main.rs
224
src/main.rs
|
@ -1,11 +1,15 @@
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use clap::Command;
|
use clap::Command;
|
||||||
|
#[cfg(feature = "imap-backend")]
|
||||||
|
use pimalaya_email::ImapBackend;
|
||||||
use pimalaya_email::{
|
use pimalaya_email::{
|
||||||
BackendBuilder, BackendConfig, ImapBackend, SenderBuilder, DEFAULT_INBOX_FOLDER,
|
BackendBuilder, BackendConfig, BackendSyncBuilder, SenderBuilder, DEFAULT_INBOX_FOLDER,
|
||||||
};
|
};
|
||||||
use std::env;
|
use std::env;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
#[cfg(feature = "imap-backend")]
|
||||||
|
use himalaya::imap;
|
||||||
use himalaya::{
|
use himalaya::{
|
||||||
account, cache, compl,
|
account, cache, compl,
|
||||||
config::{self, DeserializedConfig},
|
config::{self, DeserializedConfig},
|
||||||
|
@ -14,9 +18,6 @@ use himalaya::{
|
||||||
tpl, IdMapper,
|
tpl, IdMapper,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "imap-backend")]
|
|
||||||
use himalaya::imap;
|
|
||||||
|
|
||||||
fn create_app() -> Command {
|
fn create_app() -> Command {
|
||||||
let app = Command::new(env!("CARGO_PKG_NAME"))
|
let app = Command::new(env!("CARGO_PKG_NAME"))
|
||||||
.version(env!("CARGO_PKG_VERSION"))
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
@ -42,7 +43,8 @@ fn create_app() -> Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::single_match)]
|
#[allow(clippy::single_match)]
|
||||||
fn main() -> Result<()> {
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
let default_env_filter = env_logger::DEFAULT_FILTER_ENV;
|
let default_env_filter = env_logger::DEFAULT_FILTER_ENV;
|
||||||
env_logger::init_from_env(env_logger::Env::default().filter_or(default_env_filter, "off"));
|
env_logger::init_from_env(env_logger::Env::default().filter_or(default_env_filter, "off"));
|
||||||
|
|
||||||
|
@ -52,8 +54,8 @@ fn main() -> Result<()> {
|
||||||
let url = Url::parse(&raw_args[1])?;
|
let url = Url::parse(&raw_args[1])?;
|
||||||
let config = DeserializedConfig::from_opt_path(None)?;
|
let config = DeserializedConfig::from_opt_path(None)?;
|
||||||
let account_config = config.to_account_config(None)?;
|
let account_config = config.to_account_config(None)?;
|
||||||
let mut backend = BackendBuilder::new().build(&account_config)?;
|
let mut backend = BackendBuilder::new(account_config.clone()).build()?;
|
||||||
let mut sender = SenderBuilder::new().build(&account_config)?;
|
let mut sender = SenderBuilder::new(account_config.clone()).build()?;
|
||||||
let mut printer = StdoutPrinter::default();
|
let mut printer = StdoutPrinter::default();
|
||||||
|
|
||||||
return email::handlers::mailto(
|
return email::handlers::mailto(
|
||||||
|
@ -68,7 +70,7 @@ fn main() -> Result<()> {
|
||||||
let app = create_app();
|
let app = create_app();
|
||||||
let m = app.get_matches();
|
let m = app.get_matches();
|
||||||
|
|
||||||
// checks completion command before configs
|
// check completion command before configs
|
||||||
// https://github.com/soywod/himalaya/issues/115
|
// https://github.com/soywod/himalaya/issues/115
|
||||||
match compl::args::matches(&m)? {
|
match compl::args::matches(&m)? {
|
||||||
Some(compl::args::Cmd::Generate(shell)) => {
|
Some(compl::args::Cmd::Generate(shell)) => {
|
||||||
|
@ -77,7 +79,7 @@ fn main() -> Result<()> {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
// also checks man command before configs
|
// check also man command before configs
|
||||||
match man::args::matches(&m)? {
|
match man::args::matches(&m)? {
|
||||||
Some(man::args::Cmd::GenerateAll(dir)) => {
|
Some(man::args::Cmd::GenerateAll(dir)) => {
|
||||||
return man::handlers::generate(dir, create_app());
|
return man::handlers::generate(dir, create_app());
|
||||||
|
@ -85,53 +87,47 @@ fn main() -> Result<()> {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
// inits config
|
|
||||||
let config = DeserializedConfig::from_opt_path(config::args::parse_arg(&m))?;
|
let config = DeserializedConfig::from_opt_path(config::args::parse_arg(&m))?;
|
||||||
let account_config = config.to_account_config(account::args::parse_arg(&m))?;
|
let account_config = config.to_account_config(account::args::parse_arg(&m))?;
|
||||||
|
let account_name = account_config.name.clone();
|
||||||
let folder = folder::args::parse_source_arg(&m);
|
let folder = folder::args::parse_source_arg(&m);
|
||||||
|
let disable_cache = cache::args::parse_disable_cache_flag(&m);
|
||||||
|
|
||||||
|
// FIXME: find why account config cannot be borrowed
|
||||||
|
// let backend_builder =
|
||||||
|
// BackendBuilder::new(Cow::Borrowed(&account_config)).with_cache_disabled(disable_cache);
|
||||||
|
let backend_builder =
|
||||||
|
BackendBuilder::new(account_config.clone()).with_cache_disabled(disable_cache);
|
||||||
|
let sender_builder = SenderBuilder::new(account_config.clone());
|
||||||
|
let mut printer = StdoutPrinter::try_from(&m)?;
|
||||||
|
|
||||||
// checks IMAP commands
|
|
||||||
#[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
if let BackendConfig::Imap(imap_config) = &account_config.backend {
|
if let BackendConfig::Imap(imap_config) = &account_config.backend {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
|
|
||||||
// FIXME: find a way to downcast `backend` instead of
|
|
||||||
// recreating an instance.
|
|
||||||
match imap::args::matches(&m)? {
|
match imap::args::matches(&m)? {
|
||||||
Some(imap::args::Cmd::Notify(keepalive)) => {
|
Some(imap::args::Cmd::Notify(keepalive)) => {
|
||||||
let imap = ImapBackend::new(account_config.clone(), imap_config.clone())?;
|
let mut backend =
|
||||||
return imap::handlers::notify(&imap, &folder, keepalive);
|
ImapBackend::new(account_config.clone(), imap_config.clone(), None)?;
|
||||||
|
return imap::handlers::notify(&mut backend, &folder, keepalive);
|
||||||
}
|
}
|
||||||
Some(imap::args::Cmd::Watch(keepalive)) => {
|
Some(imap::args::Cmd::Watch(keepalive)) => {
|
||||||
let imap = ImapBackend::new(account_config.clone(), imap_config.clone())?;
|
let mut backend =
|
||||||
return imap::handlers::watch(&imap, &folder, keepalive);
|
ImapBackend::new(account_config.clone(), imap_config.clone(), None)?;
|
||||||
|
return imap::handlers::watch(&mut backend, &folder, keepalive);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// inits services
|
|
||||||
let disable_cache = cache::args::parse_disable_cache_flag(&m);
|
|
||||||
let mut printer = StdoutPrinter::try_from(&m)?;
|
|
||||||
|
|
||||||
// checks account commands
|
|
||||||
match account::args::matches(&m)? {
|
match account::args::matches(&m)? {
|
||||||
Some(account::args::Cmd::List(max_width)) => {
|
Some(account::args::Cmd::List(max_width)) => {
|
||||||
return account::handlers::list(max_width, &account_config, &config, &mut printer);
|
return account::handlers::list(max_width, &account_config, &config, &mut printer);
|
||||||
}
|
}
|
||||||
Some(account::args::Cmd::Sync(folders_strategy, dry_run)) => {
|
Some(account::args::Cmd::Sync(strategy, dry_run)) => {
|
||||||
let backend = BackendBuilder::new()
|
let sync_builder = BackendSyncBuilder::new(account_config, backend_builder)?
|
||||||
.sessions_pool_size(8)
|
.with_some_folders_strategy(strategy)
|
||||||
.disable_cache(true)
|
.with_dry_run(dry_run);
|
||||||
.build(&account_config)?;
|
account::handlers::sync(&mut printer, sync_builder, dry_run)?;
|
||||||
account::handlers::sync(
|
|
||||||
&account_config,
|
|
||||||
&mut printer,
|
|
||||||
backend.as_ref(),
|
|
||||||
folders_strategy,
|
|
||||||
dry_run,
|
|
||||||
)?;
|
|
||||||
backend.close()?;
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Some(account::args::Cmd::Configure(reset)) => {
|
Some(account::args::Cmd::Configure(reset)) => {
|
||||||
|
@ -147,15 +143,11 @@ fn main() -> Result<()> {
|
||||||
.ok_or_else(|| anyhow!("the folder argument is missing"))
|
.ok_or_else(|| anyhow!("the folder argument is missing"))
|
||||||
.context("cannot create folder")?;
|
.context("cannot create folder")?;
|
||||||
let folder = account_config.folder_alias(folder)?;
|
let folder = account_config.folder_alias(folder)?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.build()?;
|
||||||
.disable_cache(disable_cache)
|
|
||||||
.build(&account_config)?;
|
|
||||||
return folder::handlers::create(&mut printer, backend.as_mut(), &folder);
|
return folder::handlers::create(&mut printer, backend.as_mut(), &folder);
|
||||||
}
|
}
|
||||||
Some(folder::args::Cmd::List(max_width)) => {
|
Some(folder::args::Cmd::List(max_width)) => {
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.build()?;
|
||||||
.disable_cache(disable_cache)
|
|
||||||
.build(&account_config)?;
|
|
||||||
return folder::handlers::list(
|
return folder::handlers::list(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -165,9 +157,7 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(folder::args::Cmd::Expunge) => {
|
Some(folder::args::Cmd::Expunge) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.build()?;
|
||||||
.disable_cache(disable_cache)
|
|
||||||
.build(&account_config)?;
|
|
||||||
return folder::handlers::expunge(&mut printer, backend.as_mut(), &folder);
|
return folder::handlers::expunge(&mut printer, backend.as_mut(), &folder);
|
||||||
}
|
}
|
||||||
Some(folder::args::Cmd::Delete) => {
|
Some(folder::args::Cmd::Delete) => {
|
||||||
|
@ -175,9 +165,7 @@ fn main() -> Result<()> {
|
||||||
.ok_or_else(|| anyhow!("the folder argument is missing"))
|
.ok_or_else(|| anyhow!("the folder argument is missing"))
|
||||||
.context("cannot delete folder")?;
|
.context("cannot delete folder")?;
|
||||||
let folder = account_config.folder_alias(folder)?;
|
let folder = account_config.folder_alias(folder)?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.build()?;
|
||||||
.disable_cache(disable_cache)
|
|
||||||
.build(&account_config)?;
|
|
||||||
return folder::handlers::delete(&mut printer, backend.as_mut(), &folder);
|
return folder::handlers::delete(&mut printer, backend.as_mut(), &folder);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
@ -187,10 +175,8 @@ fn main() -> Result<()> {
|
||||||
match email::args::matches(&m)? {
|
match email::args::matches(&m)? {
|
||||||
Some(email::args::Cmd::Attachments(ids)) => {
|
Some(email::args::Cmd::Attachments(ids)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return email::handlers::attachments(
|
return email::handlers::attachments(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -202,10 +188,9 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(email::args::Cmd::Copy(ids, to_folder)) => {
|
Some(email::args::Cmd::Copy(ids, to_folder)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return email::handlers::copy(
|
return email::handlers::copy(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -218,10 +203,9 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(email::args::Cmd::Delete(ids)) => {
|
Some(email::args::Cmd::Delete(ids)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return email::handlers::delete(
|
return email::handlers::delete(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -233,11 +217,10 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(email::args::Cmd::Forward(id, headers, body)) => {
|
Some(email::args::Cmd::Forward(id, headers, body)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let mut sender = sender_builder.build()?;
|
||||||
.build(&account_config)?;
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
let mut sender = SenderBuilder::new().build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return email::handlers::forward(
|
return email::handlers::forward(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -252,10 +235,9 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(email::args::Cmd::List(max_width, page_size, page)) => {
|
Some(email::args::Cmd::List(max_width, page_size, page)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return email::handlers::list(
|
return email::handlers::list(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -269,10 +251,9 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(email::args::Cmd::Move(ids, to_folder)) => {
|
Some(email::args::Cmd::Move(ids, to_folder)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return email::handlers::move_(
|
return email::handlers::move_(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -285,10 +266,9 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(email::args::Cmd::Read(ids, text_mime, raw, headers)) => {
|
Some(email::args::Cmd::Read(ids, text_mime, raw, headers)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return email::handlers::read(
|
return email::handlers::read(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -303,11 +283,10 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(email::args::Cmd::Reply(id, all, headers, body)) => {
|
Some(email::args::Cmd::Reply(id, all, headers, body)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let mut sender = sender_builder.build()?;
|
||||||
.build(&account_config)?;
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
let mut sender = SenderBuilder::new().build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return email::handlers::reply(
|
return email::handlers::reply(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -323,10 +302,9 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(email::args::Cmd::Save(raw_email)) => {
|
Some(email::args::Cmd::Save(raw_email)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return email::handlers::save(
|
return email::handlers::save(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -338,10 +316,9 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(email::args::Cmd::Search(query, max_width, page_size, page)) => {
|
Some(email::args::Cmd::Search(query, max_width, page_size, page)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return email::handlers::search(
|
return email::handlers::search(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -356,10 +333,9 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(email::args::Cmd::Sort(criteria, query, max_width, page_size, page)) => {
|
Some(email::args::Cmd::Sort(criteria, query, max_width, page_size, page)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return email::handlers::sort(
|
return email::handlers::sort(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -374,10 +350,8 @@ fn main() -> Result<()> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Some(email::args::Cmd::Send(raw_email)) => {
|
Some(email::args::Cmd::Send(raw_email)) => {
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.build()?;
|
||||||
.disable_cache(disable_cache)
|
let mut sender = sender_builder.build()?;
|
||||||
.build(&account_config)?;
|
|
||||||
let mut sender = SenderBuilder::new().build(&account_config)?;
|
|
||||||
return email::handlers::send(
|
return email::handlers::send(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -389,10 +363,9 @@ fn main() -> Result<()> {
|
||||||
Some(email::args::Cmd::Flag(m)) => match m {
|
Some(email::args::Cmd::Flag(m)) => match m {
|
||||||
Some(flag::args::Cmd::Set(ids, ref flags)) => {
|
Some(flag::args::Cmd::Set(ids, ref flags)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return flag::handlers::set(
|
return flag::handlers::set(
|
||||||
&mut printer,
|
&mut printer,
|
||||||
&id_mapper,
|
&id_mapper,
|
||||||
|
@ -404,10 +377,9 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(flag::args::Cmd::Add(ids, ref flags)) => {
|
Some(flag::args::Cmd::Add(ids, ref flags)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return flag::handlers::add(
|
return flag::handlers::add(
|
||||||
&mut printer,
|
&mut printer,
|
||||||
&id_mapper,
|
&id_mapper,
|
||||||
|
@ -419,10 +391,9 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(flag::args::Cmd::Remove(ids, ref flags)) => {
|
Some(flag::args::Cmd::Remove(ids, ref flags)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return flag::handlers::remove(
|
return flag::handlers::remove(
|
||||||
&mut printer,
|
&mut printer,
|
||||||
&id_mapper,
|
&id_mapper,
|
||||||
|
@ -437,10 +408,9 @@ fn main() -> Result<()> {
|
||||||
Some(email::args::Cmd::Tpl(m)) => match m {
|
Some(email::args::Cmd::Tpl(m)) => match m {
|
||||||
Some(tpl::args::Cmd::Forward(id, headers, body)) => {
|
Some(tpl::args::Cmd::Forward(id, headers, body)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return tpl::handlers::forward(
|
return tpl::handlers::forward(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -457,10 +427,9 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(tpl::args::Cmd::Reply(id, all, headers, body)) => {
|
Some(tpl::args::Cmd::Reply(id, all, headers, body)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return tpl::handlers::reply(
|
return tpl::handlers::reply(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -475,10 +444,9 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(tpl::args::Cmd::Save(tpl)) => {
|
Some(tpl::args::Cmd::Save(tpl)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||||
.build(&account_config)?;
|
|
||||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
|
||||||
return tpl::handlers::save(
|
return tpl::handlers::save(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -490,10 +458,8 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Some(tpl::args::Cmd::Send(tpl)) => {
|
Some(tpl::args::Cmd::Send(tpl)) => {
|
||||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.clone().into_build()?;
|
||||||
.disable_cache(disable_cache)
|
let mut sender = sender_builder.build()?;
|
||||||
.build(&account_config)?;
|
|
||||||
let mut sender = SenderBuilder::new().build(&account_config)?;
|
|
||||||
return tpl::handlers::send(
|
return tpl::handlers::send(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
@ -506,10 +472,8 @@ fn main() -> Result<()> {
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
Some(email::args::Cmd::Write(headers, body)) => {
|
Some(email::args::Cmd::Write(headers, body)) => {
|
||||||
let mut backend = BackendBuilder::new()
|
let mut backend = backend_builder.build()?;
|
||||||
.disable_cache(disable_cache)
|
let mut sender = sender_builder.build()?;
|
||||||
.build(&account_config)?;
|
|
||||||
let mut sender = SenderBuilder::new().build(&account_config)?;
|
|
||||||
return email::handlers::write(
|
return email::handlers::write(
|
||||||
&account_config,
|
&account_config,
|
||||||
&mut printer,
|
&mut printer,
|
||||||
|
|
Loading…
Reference in a new issue