mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-22 02:50:19 +00:00
bump deps, make global config option repeatable
This commit is contained in:
parent
3868c62511
commit
7ee710634b
10 changed files with 374 additions and 359 deletions
|
@ -13,9 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
### Changed
|
||||
|
||||
- Made the global `--config|-c` option repeatable: the first option is considered the path to the main config, and successive options are considered partial overrides [#184].
|
||||
- Changed the `envelope list` options (see `envelope list --help` for more details):
|
||||
- the folder argument became a flag `--folder <name>`
|
||||
- the query argument has been added at the end of the command to filter and sort results [#39]
|
||||
- The folder argument became a flag `--folder <name>`.
|
||||
- The query argument has been added at the end of the command to filter and sort results [#39].
|
||||
|
||||
### Fixed
|
||||
|
||||
|
@ -807,4 +808,5 @@ Few major concepts changed:
|
|||
[#95]: https://todo.sr.ht/~soywod/pimalaya/95
|
||||
[#172]: https://todo.sr.ht/~soywod/pimalaya/172
|
||||
[#173]: https://todo.sr.ht/~soywod/pimalaya/173
|
||||
[#184]: https://todo.sr.ht/~soywod/pimalaya/184
|
||||
[#188]: https://todo.sr.ht/~soywod/pimalaya/188
|
||||
|
|
446
Cargo.lock
generated
446
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
33
Cargo.toml
33
Cargo.toml
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "himalaya"
|
||||
description = "CLI to manage emails"
|
||||
version = "1.0.0-beta.3"
|
||||
version = "1.0.0-beta.4"
|
||||
authors = ["soywod <clement.douin@posteo.net>"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -13,7 +13,7 @@ repository = "https://github.com/soywod/himalaya/"
|
|||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
rustdoc-args = ["--cfg", "docsrs", "--document-private-items"]
|
||||
|
||||
[features]
|
||||
default = [
|
||||
|
@ -46,7 +46,6 @@ pgp-gpg = ["email-lib/pgp-gpg", "mml-lib/pgp-gpg", "pgp"]
|
|||
pgp-native = ["email-lib/pgp-native", "mml-lib/pgp-native", "pgp"]
|
||||
|
||||
[dev-dependencies]
|
||||
async-trait = "0.1"
|
||||
tempfile = "3.3"
|
||||
|
||||
[dependencies]
|
||||
|
@ -60,29 +59,30 @@ clap_mangen = "0.2"
|
|||
console = "0.15.2"
|
||||
dialoguer = "0.10.2"
|
||||
dirs = "4"
|
||||
email-lib = { version = "=0.22.3", default-features = false }
|
||||
email-lib = { version = "=0.22.3", default-features = false, features = ["derive"] }
|
||||
email_address = "0.2.4"
|
||||
env_logger = "0.8"
|
||||
erased-serde = "0.3"
|
||||
indicatif = "0.17"
|
||||
keyring-lib = "=0.3.2"
|
||||
keyring-lib = { version = "=0.4.0", features = ["derive"] }
|
||||
log = "0.4"
|
||||
mail-builder = "0.3"
|
||||
md5 = "0.7"
|
||||
mml-lib = { version = "=1.0.7", default-features = false }
|
||||
mml-lib = { version = "=1.0.8", default-features = false, features = ["derive"] }
|
||||
oauth-lib = "=0.1.0"
|
||||
once_cell = "1.16"
|
||||
process-lib = "=0.3.1"
|
||||
secret-lib = "=0.3.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
process-lib = { version = "=0.4.1", features = ["derive"] }
|
||||
secret-lib = { version = "=0.4.1", features = ["derive"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde-toml-merge = "0.3"
|
||||
serde_json = "1"
|
||||
shellexpand-utils = "=0.2.0"
|
||||
sled = "=0.34.7"
|
||||
termcolor = "1"
|
||||
terminal_size = "0.1"
|
||||
tokio = { version = "1.23", default-features = false, features = ["macros", "rt-multi-thread"] }
|
||||
toml = "0.7.4"
|
||||
toml_edit = "0.19.8"
|
||||
toml = "0.8"
|
||||
toml_edit = "0.22"
|
||||
unicode-width = "0.1"
|
||||
url = "2.2"
|
||||
uuid = { version = "0.8", features = ["v4"] }
|
||||
|
@ -91,5 +91,14 @@ uuid = { version = "0.8", features = ["v4"] }
|
|||
version = "0.1"
|
||||
|
||||
[patch.crates-io]
|
||||
email-lib = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||
# waiting for alpha 7
|
||||
chumsky = { git = "https://github.com/zesterer/chumsky.git", rev = "6837537" }
|
||||
email-lib = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||
email-macros = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||
keyring-lib = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||
mml-lib = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||
oauth-lib = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||
pgp-lib = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||
process-lib = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||
secret-lib = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||
shellexpand-utils = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||
|
|
37
src/cli.rs
37
src/cli.rs
|
@ -25,17 +25,19 @@ pub struct Cli {
|
|||
#[command(subcommand)]
|
||||
pub command: Option<HimalayaCommand>,
|
||||
|
||||
/// Override the default configuration file path
|
||||
/// Override the default configuration file path.
|
||||
///
|
||||
/// The given path is shell-expanded then canonicalized (if
|
||||
/// applicable). If the path does not point to a valid file, the
|
||||
/// wizard will propose to assist you in the creation of the
|
||||
/// configuration file.
|
||||
/// The given paths are shell-expanded then canonicalized (if
|
||||
/// applicable). If the first path does not point to a valid file,
|
||||
/// the wizard will propose to assist you in the creation of the
|
||||
/// configuration file. Other paths are merged with the first one,
|
||||
/// which allows you to separate your public config from your
|
||||
/// private(s) one(s).
|
||||
#[arg(short, long = "config", global = true)]
|
||||
#[arg(value_name = "PATH", value_parser = config::path_parser)]
|
||||
pub config_path: Option<PathBuf>,
|
||||
pub config_paths: Vec<PathBuf>,
|
||||
|
||||
/// Customize the output format
|
||||
/// Customize the output format.
|
||||
///
|
||||
/// The output format determine how to display commands output to
|
||||
/// the terminal.
|
||||
|
@ -116,39 +118,34 @@ pub enum HimalayaCommand {
|
|||
}
|
||||
|
||||
impl HimalayaCommand {
|
||||
#[allow(unused)]
|
||||
pub async fn execute(
|
||||
self,
|
||||
printer: &mut impl Printer,
|
||||
config_path: Option<&PathBuf>,
|
||||
) -> Result<()> {
|
||||
pub async fn execute(self, printer: &mut impl Printer, config_paths: &[PathBuf]) -> Result<()> {
|
||||
match self {
|
||||
Self::Account(cmd) => {
|
||||
let config = TomlConfig::from_some_path_or_default(config_path).await?;
|
||||
let config = TomlConfig::from_paths_or_default(config_paths).await?;
|
||||
cmd.execute(printer, &config).await
|
||||
}
|
||||
Self::Folder(cmd) => {
|
||||
let config = TomlConfig::from_some_path_or_default(config_path).await?;
|
||||
let config = TomlConfig::from_paths_or_default(config_paths).await?;
|
||||
cmd.execute(printer, &config).await
|
||||
}
|
||||
Self::Envelope(cmd) => {
|
||||
let config = TomlConfig::from_some_path_or_default(config_path).await?;
|
||||
let config = TomlConfig::from_paths_or_default(config_paths).await?;
|
||||
cmd.execute(printer, &config).await
|
||||
}
|
||||
Self::Flag(cmd) => {
|
||||
let config = TomlConfig::from_some_path_or_default(config_path).await?;
|
||||
let config = TomlConfig::from_paths_or_default(config_paths).await?;
|
||||
cmd.execute(printer, &config).await
|
||||
}
|
||||
Self::Message(cmd) => {
|
||||
let config = TomlConfig::from_some_path_or_default(config_path).await?;
|
||||
let config = TomlConfig::from_paths_or_default(config_paths).await?;
|
||||
cmd.execute(printer, &config).await
|
||||
}
|
||||
Self::Attachment(cmd) => {
|
||||
let config = TomlConfig::from_some_path_or_default(config_path).await?;
|
||||
let config = TomlConfig::from_paths_or_default(config_paths).await?;
|
||||
cmd.execute(printer, &config).await
|
||||
}
|
||||
Self::Template(cmd) => {
|
||||
let config = TomlConfig::from_some_path_or_default(config_path).await?;
|
||||
let config = TomlConfig::from_paths_or_default(config_paths).await?;
|
||||
cmd.execute(printer, &config).await
|
||||
}
|
||||
Self::Manual(cmd) => cmd.execute(printer).await,
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
pub mod wizard;
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use dirs::{config_dir, home_dir};
|
||||
use email::{
|
||||
account::config::AccountConfig, config::Config, envelope::config::EnvelopeConfig,
|
||||
flag::config::FlagConfig, folder::config::FolderConfig, message::config::MessageConfig,
|
||||
};
|
||||
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_toml_merge::merge;
|
||||
use shellexpand_utils::{canonicalize, expand};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use toml;
|
||||
use std::{collections::HashMap, fs, path::PathBuf, sync::Arc};
|
||||
use toml::{self, Value};
|
||||
|
||||
#[cfg(feature = "account-sync")]
|
||||
use crate::backend::BackendKind;
|
||||
|
@ -34,14 +30,48 @@ pub struct TomlConfig {
|
|||
}
|
||||
|
||||
impl TomlConfig {
|
||||
/// Read and parse the TOML configuration at the given path.
|
||||
/// Read and parse the TOML configuration at the given paths.
|
||||
///
|
||||
/// Returns an error if the configuration file cannot be read or
|
||||
/// if its content cannot be parsed.
|
||||
fn from_path(path: &Path) -> Result<Self> {
|
||||
let content =
|
||||
fs::read_to_string(path).context(format!("cannot read config file at {path:?}"))?;
|
||||
toml::from_str(&content).context(format!("cannot parse config file at {path:?}"))
|
||||
/// Returns an error if a configuration file cannot be read or if
|
||||
/// a content cannot be parsed.
|
||||
fn from_paths(paths: &[PathBuf]) -> Result<Self> {
|
||||
match paths.len() {
|
||||
0 => {
|
||||
// should never happen
|
||||
bail!("cannot read config file from empty paths");
|
||||
}
|
||||
1 => {
|
||||
let path = &paths[0];
|
||||
|
||||
let ref content = fs::read_to_string(path)
|
||||
.context(format!("cannot read config file at {path:?}"))?;
|
||||
|
||||
toml::from_str(content).context(format!("cannot parse config file at {path:?}"))
|
||||
}
|
||||
_ => {
|
||||
let path = &paths[0];
|
||||
|
||||
let mut merged_content = fs::read_to_string(path)
|
||||
.context(format!("cannot read config file at {path:?}"))?
|
||||
.parse::<Value>()?;
|
||||
|
||||
for path in &paths[1..] {
|
||||
match fs::read_to_string(path) {
|
||||
Ok(content) => {
|
||||
merged_content = merge(merged_content, content.parse()?).unwrap();
|
||||
}
|
||||
Err(err) => {
|
||||
debug!("skipping subconfig file at {path:?}: {err}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
merged_content
|
||||
.try_into()
|
||||
.context(format!("cannot parse merged config file at {path:?}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create and save a TOML configuration using the wizard.
|
||||
|
@ -51,7 +81,7 @@ impl TomlConfig {
|
|||
/// program stops.
|
||||
///
|
||||
/// NOTE: the wizard can only be used with interactive shells.
|
||||
async fn from_wizard(path: PathBuf) -> Result<Self> {
|
||||
async fn from_wizard(path: &PathBuf) -> Result<Self> {
|
||||
use dialoguer::Confirm;
|
||||
use std::process;
|
||||
|
||||
|
@ -75,8 +105,8 @@ impl TomlConfig {
|
|||
/// Read and parse the TOML configuration from default paths.
|
||||
pub async fn from_default_paths() -> Result<Self> {
|
||||
match Self::first_valid_default_path() {
|
||||
Some(path) => Self::from_path(&path),
|
||||
None => Self::from_wizard(Self::default_path()?).await,
|
||||
Some(path) => Self::from_paths(&[path]),
|
||||
None => Self::from_wizard(&Self::default_path()?).await,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,11 +122,11 @@ impl TomlConfig {
|
|||
/// If no path is given, then either read and parse the TOML
|
||||
/// configuration at the first valid default path, otherwise
|
||||
/// create it using the wizard. wizard.
|
||||
pub async fn from_some_path_or_default(path: Option<impl Into<PathBuf>>) -> Result<Self> {
|
||||
match path.map(Into::into) {
|
||||
Some(ref path) if path.exists() => Self::from_path(path),
|
||||
Some(path) => Self::from_wizard(path).await,
|
||||
_ => Self::from_default_paths().await,
|
||||
pub async fn from_paths_or_default(paths: &[PathBuf]) -> Result<Self> {
|
||||
match paths.len() {
|
||||
0 => Self::from_default_paths().await,
|
||||
_ if paths[0].exists() => Self::from_paths(paths),
|
||||
_ => Self::from_wizard(&paths[0]).await,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,14 +187,14 @@ impl TomlConfig {
|
|||
if let Some(imap_config) = toml_account_config.imap.as_mut() {
|
||||
imap_config
|
||||
.auth
|
||||
.replace_undefined_keyring_entries(&account_name);
|
||||
.replace_undefined_keyring_entries(&account_name)?;
|
||||
}
|
||||
|
||||
#[cfg(feature = "smtp")]
|
||||
if let Some(smtp_config) = toml_account_config.smtp.as_mut() {
|
||||
smtp_config
|
||||
.auth
|
||||
.replace_undefined_keyring_entries(&account_name);
|
||||
.replace_undefined_keyring_entries(&account_name)?;
|
||||
}
|
||||
|
||||
Ok((account_name, toml_account_config))
|
||||
|
|
|
@ -2,7 +2,7 @@ use anyhow::Result;
|
|||
use dialoguer::{Confirm, Input, Select};
|
||||
use shellexpand_utils::expand;
|
||||
use std::{fs, path::PathBuf, process};
|
||||
use toml_edit::{Document, Item};
|
||||
use toml_edit::{DocumentMut, Item};
|
||||
|
||||
use crate::{account, ui::THEME};
|
||||
|
||||
|
@ -31,7 +31,7 @@ macro_rules! wizard_log {
|
|||
};
|
||||
}
|
||||
|
||||
pub(crate) async fn configure(path: PathBuf) -> Result<TomlConfig> {
|
||||
pub(crate) async fn configure(path: &PathBuf) -> Result<TomlConfig> {
|
||||
wizard_log!("Configuring your first account:");
|
||||
|
||||
let mut config = TomlConfig::default();
|
||||
|
@ -103,7 +103,7 @@ pub(crate) async fn configure(path: PathBuf) -> Result<TomlConfig> {
|
|||
}
|
||||
|
||||
fn pretty_serialize(config: &TomlConfig) -> Result<String> {
|
||||
let mut doc: Document = toml::to_string(&config)?.parse()?;
|
||||
let mut doc: DocumentMut = toml::to_string(&config)?.parse()?;
|
||||
|
||||
doc.iter_mut().for_each(|(_, item)| {
|
||||
if let Some(item) = item.as_table_mut() {
|
||||
|
@ -299,7 +299,9 @@ folder.sync.permissions.delete = true
|
|||
host: "localhost".into(),
|
||||
port: 143,
|
||||
login: "test@localhost".into(),
|
||||
auth: ImapAuthConfig::Passwd(PasswdConfig(Secret::new_cmd("pass show test"))),
|
||||
auth: ImapAuthConfig::Passwd(PasswdConfig(Secret::new_command(
|
||||
"pass show test",
|
||||
))),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
|
@ -330,7 +332,7 @@ imap.passwd.cmd = "pass show test"
|
|||
host: "localhost".into(),
|
||||
port: 143,
|
||||
login: "test@localhost".into(),
|
||||
auth: ImapAuthConfig::Passwd(PasswdConfig(Secret::new_cmd(vec![
|
||||
auth: ImapAuthConfig::Passwd(PasswdConfig(Secret::new_command(vec![
|
||||
"pass show test",
|
||||
"tr -d '[:blank:]'",
|
||||
]))),
|
||||
|
@ -424,7 +426,9 @@ maildir.root-dir = "/tmp/test"
|
|||
host: "localhost".into(),
|
||||
port: 143,
|
||||
login: "test@localhost".into(),
|
||||
auth: SmtpAuthConfig::Passwd(PasswdConfig(Secret::new_cmd("pass show test"))),
|
||||
auth: SmtpAuthConfig::Passwd(PasswdConfig(Secret::new_command(
|
||||
"pass show test",
|
||||
))),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
|
@ -455,7 +459,7 @@ smtp.passwd.cmd = "pass show test"
|
|||
host: "localhost".into(),
|
||||
port: 143,
|
||||
login: "test@localhost".into(),
|
||||
auth: SmtpAuthConfig::Passwd(PasswdConfig(Secret::new_cmd(vec![
|
||||
auth: SmtpAuthConfig::Passwd(PasswdConfig(Secret::new_command(vec![
|
||||
"pass show test",
|
||||
"tr -d '[:blank:]'",
|
||||
]))),
|
||||
|
|
|
@ -163,10 +163,10 @@ pub(crate) async fn configure(
|
|||
.with_prompt("IMAP OAuth 2.0 client secret")
|
||||
.interact()?;
|
||||
config.client_secret =
|
||||
Secret::new_keyring_entry(format!("{account_name}-imap-oauth2-client-secret"));
|
||||
Secret::try_new_keyring_entry(format!("{account_name}-imap-oauth2-client-secret"))?;
|
||||
config
|
||||
.client_secret
|
||||
.set_keyring_entry_secret(&client_secret)
|
||||
.set_only_keyring(&client_secret)
|
||||
.await?;
|
||||
|
||||
let default_auth_url = autoconfig_oauth2
|
||||
|
@ -278,19 +278,13 @@ pub(crate) async fn configure(
|
|||
.await?;
|
||||
|
||||
config.access_token =
|
||||
Secret::new_keyring_entry(format!("{account_name}-imap-oauth2-access-token"));
|
||||
config
|
||||
.access_token
|
||||
.set_keyring_entry_secret(access_token)
|
||||
.await?;
|
||||
Secret::try_new_keyring_entry(format!("{account_name}-imap-oauth2-access-token"))?;
|
||||
config.access_token.set_only_keyring(access_token).await?;
|
||||
|
||||
if let Some(refresh_token) = &refresh_token {
|
||||
config.refresh_token =
|
||||
Secret::new_keyring_entry(format!("{account_name}-imap-oauth2-refresh-token"));
|
||||
config
|
||||
.refresh_token
|
||||
.set_keyring_entry_secret(refresh_token)
|
||||
.await?;
|
||||
Secret::try_new_keyring_entry(format!("{account_name}-imap-oauth2-refresh-token"))?;
|
||||
config.refresh_token.set_only_keyring(refresh_token).await?;
|
||||
}
|
||||
|
||||
ImapAuthConfig::OAuth2(config)
|
||||
|
@ -303,14 +297,14 @@ pub(crate) async fn configure(
|
|||
|
||||
let secret = match secret_idx {
|
||||
Some(idx) if SECRETS[idx] == KEYRING => {
|
||||
let secret = Secret::new_keyring_entry(format!("{account_name}-imap-passwd"));
|
||||
let secret = Secret::try_new_keyring_entry(format!("{account_name}-imap-passwd"))?;
|
||||
secret
|
||||
.set_keyring_entry_secret(prompt::passwd("IMAP password")?)
|
||||
.set_only_keyring(prompt::passwd("IMAP password")?)
|
||||
.await?;
|
||||
secret
|
||||
}
|
||||
Some(idx) if SECRETS[idx] == RAW => Secret::new_raw(prompt::passwd("IMAP password")?),
|
||||
Some(idx) if SECRETS[idx] == CMD => Secret::new_cmd(
|
||||
Some(idx) if SECRETS[idx] == CMD => Secret::new_command(
|
||||
Input::with_theme(&*THEME)
|
||||
.with_prompt("Shell command")
|
||||
.default(format!("pass show {account_name}-imap-passwd"))
|
||||
|
@ -404,10 +398,10 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Backend
|
|||
.with_prompt("IMAP OAuth 2.0 client secret")
|
||||
.interact()?;
|
||||
config.client_secret =
|
||||
Secret::new_keyring_entry(format!("{account_name}-imap-oauth2-client-secret"));
|
||||
Secret::try_new_keyring_entry(format!("{account_name}-imap-oauth2-client-secret"))?;
|
||||
config
|
||||
.client_secret
|
||||
.set_keyring_entry_secret(&client_secret)
|
||||
.set_only_keyring(&client_secret)
|
||||
.await?;
|
||||
|
||||
config.auth_url = Input::with_theme(&*THEME)
|
||||
|
@ -500,19 +494,13 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Backend
|
|||
.await?;
|
||||
|
||||
config.access_token =
|
||||
Secret::new_keyring_entry(format!("{account_name}-imap-oauth2-access-token"));
|
||||
config
|
||||
.access_token
|
||||
.set_keyring_entry_secret(access_token)
|
||||
.await?;
|
||||
Secret::try_new_keyring_entry(format!("{account_name}-imap-oauth2-access-token"))?;
|
||||
config.access_token.set_only_keyring(access_token).await?;
|
||||
|
||||
if let Some(refresh_token) = &refresh_token {
|
||||
config.refresh_token =
|
||||
Secret::new_keyring_entry(format!("{account_name}-imap-oauth2-refresh-token"));
|
||||
config
|
||||
.refresh_token
|
||||
.set_keyring_entry_secret(refresh_token)
|
||||
.await?;
|
||||
Secret::try_new_keyring_entry(format!("{account_name}-imap-oauth2-refresh-token"))?;
|
||||
config.refresh_token.set_only_keyring(refresh_token).await?;
|
||||
}
|
||||
|
||||
ImapAuthConfig::OAuth2(config)
|
||||
|
@ -525,14 +513,14 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Backend
|
|||
|
||||
let secret = match secret_idx {
|
||||
Some(idx) if SECRETS[idx] == KEYRING => {
|
||||
let secret = Secret::new_keyring_entry(format!("{account_name}-imap-passwd"));
|
||||
let secret = Secret::try_new_keyring_entry(format!("{account_name}-imap-passwd"))?;
|
||||
secret
|
||||
.set_keyring_entry_secret(prompt::passwd("IMAP password")?)
|
||||
.set_only_keyring(prompt::passwd("IMAP password")?)
|
||||
.await?;
|
||||
secret
|
||||
}
|
||||
Some(idx) if SECRETS[idx] == RAW => Secret::new_raw(prompt::passwd("IMAP password")?),
|
||||
Some(idx) if SECRETS[idx] == CMD => Secret::new_cmd(
|
||||
Some(idx) if SECRETS[idx] == CMD => Secret::new_command(
|
||||
Input::with_theme(&*THEME)
|
||||
.with_prompt("Shell command")
|
||||
.default(format!("pass show {account_name}-imap-passwd"))
|
||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -22,10 +22,11 @@ async fn main() -> Result<()> {
|
|||
|
||||
// if the first argument starts by "mailto:", execute straight the
|
||||
// mailto message command
|
||||
if let Some(ref url) = std::env::args()
|
||||
let mailto = std::env::args()
|
||||
.nth(1)
|
||||
.filter(|arg| arg.starts_with("mailto:"))
|
||||
{
|
||||
.filter(|arg| arg.starts_with("mailto:"));
|
||||
|
||||
if let Some(ref url) = mailto {
|
||||
let mut printer = StdoutPrinter::default();
|
||||
let config = TomlConfig::from_default_paths().await?;
|
||||
|
||||
|
@ -38,9 +39,9 @@ async fn main() -> Result<()> {
|
|||
let mut printer = StdoutPrinter::new(cli.output, cli.color);
|
||||
|
||||
match cli.command {
|
||||
Some(cmd) => cmd.execute(&mut printer, cli.config_path.as_ref()).await,
|
||||
Some(cmd) => cmd.execute(&mut printer, cli.config_paths.as_ref()).await,
|
||||
None => {
|
||||
let config = TomlConfig::from_some_path_or_default(cli.config_path.as_ref()).await?;
|
||||
let config = TomlConfig::from_paths_or_default(cli.config_paths.as_ref()).await?;
|
||||
ListEnvelopesCommand::default()
|
||||
.execute(&mut printer, &config)
|
||||
.await
|
||||
|
|
|
@ -163,10 +163,10 @@ pub(crate) async fn configure(
|
|||
.with_prompt("SMTP OAuth 2.0 client secret")
|
||||
.interact()?;
|
||||
config.client_secret =
|
||||
Secret::new_keyring_entry(format!("{account_name}-smtp-oauth2-client-secret"));
|
||||
Secret::try_new_keyring_entry(format!("{account_name}-smtp-oauth2-client-secret"))?;
|
||||
config
|
||||
.client_secret
|
||||
.set_keyring_entry_secret(&client_secret)
|
||||
.set_only_keyring(&client_secret)
|
||||
.await?;
|
||||
|
||||
let default_auth_url = autoconfig_oauth2
|
||||
|
@ -278,19 +278,13 @@ pub(crate) async fn configure(
|
|||
.await?;
|
||||
|
||||
config.access_token =
|
||||
Secret::new_keyring_entry(format!("{account_name}-smtp-oauth2-access-token"));
|
||||
config
|
||||
.access_token
|
||||
.set_keyring_entry_secret(access_token)
|
||||
.await?;
|
||||
Secret::try_new_keyring_entry(format!("{account_name}-smtp-oauth2-access-token"))?;
|
||||
config.access_token.set_only_keyring(access_token).await?;
|
||||
|
||||
if let Some(refresh_token) = &refresh_token {
|
||||
config.refresh_token =
|
||||
Secret::new_keyring_entry(format!("{account_name}-smtp-oauth2-refresh-token"));
|
||||
config
|
||||
.refresh_token
|
||||
.set_keyring_entry_secret(refresh_token)
|
||||
.await?;
|
||||
Secret::try_new_keyring_entry(format!("{account_name}-smtp-oauth2-refresh-token"))?;
|
||||
config.refresh_token.set_only_keyring(refresh_token).await?;
|
||||
}
|
||||
|
||||
SmtpAuthConfig::OAuth2(config)
|
||||
|
@ -303,14 +297,14 @@ pub(crate) async fn configure(
|
|||
|
||||
let secret = match secret_idx {
|
||||
Some(idx) if SECRETS[idx] == KEYRING => {
|
||||
let secret = Secret::new_keyring_entry(format!("{account_name}-smtp-passwd"));
|
||||
let secret = Secret::try_new_keyring_entry(format!("{account_name}-smtp-passwd"))?;
|
||||
secret
|
||||
.set_keyring_entry_secret(prompt::passwd("SMTP password")?)
|
||||
.set_only_keyring(prompt::passwd("SMTP password")?)
|
||||
.await?;
|
||||
secret
|
||||
}
|
||||
Some(idx) if SECRETS[idx] == RAW => Secret::new_raw(prompt::passwd("SMTP password")?),
|
||||
Some(idx) if SECRETS[idx] == CMD => Secret::new_cmd(
|
||||
Some(idx) if SECRETS[idx] == CMD => Secret::new_command(
|
||||
Input::with_theme(&*THEME)
|
||||
.with_prompt("Shell command")
|
||||
.default(format!("pass show {account_name}-smtp-passwd"))
|
||||
|
@ -403,10 +397,10 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Backend
|
|||
.with_prompt("SMTP OAuth 2.0 client secret")
|
||||
.interact()?;
|
||||
config.client_secret =
|
||||
Secret::new_keyring_entry(format!("{account_name}-smtp-oauth2-client-secret"));
|
||||
Secret::try_new_keyring_entry(format!("{account_name}-smtp-oauth2-client-secret"))?;
|
||||
config
|
||||
.client_secret
|
||||
.set_keyring_entry_secret(&client_secret)
|
||||
.set_only_keyring(&client_secret)
|
||||
.await?;
|
||||
|
||||
config.auth_url = Input::with_theme(&*THEME)
|
||||
|
@ -499,19 +493,13 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Backend
|
|||
.await?;
|
||||
|
||||
config.access_token =
|
||||
Secret::new_keyring_entry(format!("{account_name}-smtp-oauth2-access-token"));
|
||||
config
|
||||
.access_token
|
||||
.set_keyring_entry_secret(access_token)
|
||||
.await?;
|
||||
Secret::try_new_keyring_entry(format!("{account_name}-smtp-oauth2-access-token"))?;
|
||||
config.access_token.set_only_keyring(access_token).await?;
|
||||
|
||||
if let Some(refresh_token) = &refresh_token {
|
||||
config.refresh_token =
|
||||
Secret::new_keyring_entry(format!("{account_name}-smtp-oauth2-refresh-token"));
|
||||
config
|
||||
.refresh_token
|
||||
.set_keyring_entry_secret(refresh_token)
|
||||
.await?;
|
||||
Secret::try_new_keyring_entry(format!("{account_name}-smtp-oauth2-refresh-token"))?;
|
||||
config.refresh_token.set_only_keyring(refresh_token).await?;
|
||||
}
|
||||
|
||||
SmtpAuthConfig::OAuth2(config)
|
||||
|
@ -524,14 +512,14 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Backend
|
|||
|
||||
let secret = match secret_idx {
|
||||
Some(idx) if SECRETS[idx] == KEYRING => {
|
||||
let secret = Secret::new_keyring_entry(format!("{account_name}-smtp-passwd"));
|
||||
let secret = Secret::try_new_keyring_entry(format!("{account_name}-smtp-passwd"))?;
|
||||
secret
|
||||
.set_keyring_entry_secret(prompt::passwd("SMTP password")?)
|
||||
.set_only_keyring(prompt::passwd("SMTP password")?)
|
||||
.await?;
|
||||
secret
|
||||
}
|
||||
Some(idx) if SECRETS[idx] == RAW => Secret::new_raw(prompt::passwd("SMTP password")?),
|
||||
Some(idx) if SECRETS[idx] == CMD => Secret::new_cmd(
|
||||
Some(idx) if SECRETS[idx] == CMD => Secret::new_command(
|
||||
Input::with_theme(&*THEME)
|
||||
.with_prompt("Shell command")
|
||||
.default(format!("pass show {account_name}-smtp-passwd"))
|
||||
|
|
|
@ -8,7 +8,7 @@ use email::{
|
|||
};
|
||||
use log::debug;
|
||||
use mml::MmlCompilerBuilder;
|
||||
use process::SingleCmd;
|
||||
use process::SingleCommand;
|
||||
use std::{env, fs, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
|
@ -25,7 +25,7 @@ pub async fn open_with_tpl(tpl: String) -> Result<String> {
|
|||
|
||||
debug!("open editor");
|
||||
let editor = env::var("EDITOR").context("cannot get editor from env var")?;
|
||||
SingleCmd::from(format!("{editor} {}", &path.to_string_lossy()))
|
||||
SingleCommand::from(format!("{editor} {}", &path.to_string_lossy()))
|
||||
.with_output_piped(false)
|
||||
.run()
|
||||
.await
|
||||
|
|
Loading…
Reference in a new issue