mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-22 02:50:19 +00:00
generate one autoconfig per email address
This commit is contained in:
parent
1246be8a5b
commit
7eba3a5186
6 changed files with 56 additions and 39 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -1462,7 +1462,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "email-lib"
|
||||
version = "0.20.0"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d79298206bcb8ada88ed67be329711502351ad55bf143025b310139701dd01a0"
|
||||
dependencies = [
|
||||
"advisory-lock",
|
||||
"anyhow",
|
||||
|
@ -2957,7 +2959,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mml-lib"
|
||||
version = "1.0.6"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8ffcc68cd2f48395ee07fe85ec580154c6f8f22ff89972b4a1dd2452890d614"
|
||||
dependencies = [
|
||||
"async-recursion",
|
||||
"chumsky",
|
||||
|
@ -3709,7 +3713,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "process-lib"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e83db4af201454004f9cdc5fb343031f6d84bddf8a0d41348bc9e82fab1f1ee"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
|
@ -4245,7 +4251,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "secret-lib"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af8fa450b77b5d8e0ac1cf7c741e912e54b568e8dcf888d80f5502c23899aeae"
|
||||
dependencies = [
|
||||
"keyring-lib",
|
||||
"process-lib",
|
||||
|
|
|
@ -5,6 +5,7 @@ use dialoguer::Input;
|
|||
#[cfg(feature = "account-sync")]
|
||||
use email::account::sync::config::SyncConfig;
|
||||
use email_address::EmailAddress;
|
||||
use log::{debug, trace, warn};
|
||||
|
||||
#[allow(unused)]
|
||||
use crate::backend::{self, config::BackendConfig, BackendKind};
|
||||
|
@ -35,6 +36,8 @@ pub(crate) async fn configure() -> Result<Option<(String, TomlAccountConfig)>> {
|
|||
})
|
||||
.interact()?;
|
||||
|
||||
let email = &config.email;
|
||||
|
||||
config.display_name = Some(
|
||||
Input::with_theme(&*THEME)
|
||||
.with_prompt("Full display name")
|
||||
|
@ -49,7 +52,22 @@ pub(crate) async fn configure() -> Result<Option<(String, TomlAccountConfig)>> {
|
|||
.into(),
|
||||
);
|
||||
|
||||
match backend::wizard::configure(&account_name, &config.email).await? {
|
||||
let autoconfig = match autoconfig::from_addr(email).await {
|
||||
Ok(autoconfig) => {
|
||||
println!("An automatic configuration has been found for {email},");
|
||||
println!("it will be used by default for the rest of the configuration.\n");
|
||||
trace!("{autoconfig:#?}");
|
||||
Some(autoconfig)
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("cannot discover configuration from {email}: {err}");
|
||||
debug!("{err:?}");
|
||||
None
|
||||
}
|
||||
};
|
||||
let autoconfig = autoconfig.as_ref();
|
||||
|
||||
match backend::wizard::configure(&account_name, email, autoconfig).await? {
|
||||
#[cfg(feature = "imap")]
|
||||
Some(BackendConfig::Imap(imap_config)) => {
|
||||
config.imap = Some(imap_config);
|
||||
|
@ -68,7 +86,7 @@ pub(crate) async fn configure() -> Result<Option<(String, TomlAccountConfig)>> {
|
|||
_ => (),
|
||||
};
|
||||
|
||||
match backend::wizard::configure_sender(&account_name, &config.email).await? {
|
||||
match backend::wizard::configure_sender(&account_name, email, autoconfig).await? {
|
||||
#[cfg(feature = "smtp")]
|
||||
Some(BackendConfig::Smtp(smtp_config)) => {
|
||||
config.smtp = Some(smtp_config);
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use anyhow::Result;
|
||||
use autoconfig::config::Config as AutoConfig;
|
||||
use dialoguer::Select;
|
||||
use log::{debug, warn};
|
||||
use std::sync::OnceLock;
|
||||
|
||||
#[cfg(feature = "imap")]
|
||||
use crate::imap;
|
||||
|
@ -34,26 +32,10 @@ const SEND_MESSAGE_BACKEND_KINDS: &[BackendKind] = &[
|
|||
BackendKind::Sendmail,
|
||||
];
|
||||
|
||||
static AUTOCONFIG: OnceLock<AutoConfig> = OnceLock::new();
|
||||
|
||||
#[cfg(any(feature = "imap", feature = "smtp"))]
|
||||
pub(crate) async fn get_or_init_autoconfig(email: &str) -> Option<&AutoConfig> {
|
||||
match AUTOCONFIG.get() {
|
||||
Some(autoconfig) => Some(autoconfig),
|
||||
None => match autoconfig::from_addr(email).await {
|
||||
Ok(autoconfig) => Some(AUTOCONFIG.get_or_init(|| autoconfig)),
|
||||
Err(err) => {
|
||||
warn!("cannot discover SMTP configuration from {email}: {err}");
|
||||
debug!("{err:?}");
|
||||
None
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn configure(
|
||||
#[allow(unused)] account_name: &str,
|
||||
#[allow(unused)] email: &str,
|
||||
autoconfig: Option<&AutoConfig>,
|
||||
) -> Result<Option<BackendConfig>> {
|
||||
let kind = Select::with_theme(&*THEME)
|
||||
.with_prompt("Default email backend")
|
||||
|
@ -65,7 +47,7 @@ pub(crate) async fn configure(
|
|||
let config = match kind {
|
||||
#[cfg(feature = "imap")]
|
||||
Some(kind) if kind == BackendKind::Imap => {
|
||||
Some(imap::wizard::configure(account_name, email).await?)
|
||||
Some(imap::wizard::configure(account_name, email, autoconfig).await?)
|
||||
}
|
||||
#[cfg(feature = "maildir")]
|
||||
Some(kind) if kind == BackendKind::Maildir => Some(maildir::wizard::configure()?),
|
||||
|
@ -80,6 +62,7 @@ pub(crate) async fn configure(
|
|||
pub(crate) async fn configure_sender(
|
||||
#[allow(unused)] account_name: &str,
|
||||
#[allow(unused)] email: &str,
|
||||
autoconfig: Option<&AutoConfig>,
|
||||
) -> Result<Option<BackendConfig>> {
|
||||
let kind = Select::with_theme(&*THEME)
|
||||
.with_prompt("Backend for sending messages")
|
||||
|
@ -91,7 +74,7 @@ pub(crate) async fn configure_sender(
|
|||
let config = match kind {
|
||||
#[cfg(feature = "smtp")]
|
||||
Some(kind) if kind == BackendKind::Smtp => {
|
||||
Some(smtp::wizard::configure(account_name, email).await?)
|
||||
Some(smtp::wizard::configure(account_name, email, autoconfig).await?)
|
||||
}
|
||||
#[cfg(feature = "sendmail")]
|
||||
Some(kind) if kind == BackendKind::Sendmail => Some(sendmail::wizard::configure()?),
|
||||
|
|
|
@ -191,13 +191,15 @@ mod test {
|
|||
|
||||
use crate::{account::config::TomlAccountConfig, config::TomlConfig};
|
||||
|
||||
use super::pretty_serialize;
|
||||
|
||||
fn assert_eq(config: TomlAccountConfig, expected_toml: &str) {
|
||||
let config = TomlConfig {
|
||||
accounts: HashMap::from_iter([("test".into(), config)]),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let toml = super::pretty_serialize(&config).expect("serialize error");
|
||||
let toml = pretty_serialize(&config).expect("serialize error");
|
||||
assert_eq!(toml, expected_toml);
|
||||
|
||||
let expected_config = toml::from_str(&toml).expect("deserialize error");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::Result;
|
||||
use autoconfig::config::{AuthenticationType, SecurityType, ServerType};
|
||||
use autoconfig::config::{AuthenticationType, Config as AutoConfig, SecurityType, ServerType};
|
||||
use dialoguer::{Confirm, Input, Password, Select};
|
||||
use email::{
|
||||
account::config::{
|
||||
|
@ -12,7 +12,7 @@ use oauth::v2_0::{AuthorizationCodeGrant, Client};
|
|||
use secret::Secret;
|
||||
|
||||
use crate::{
|
||||
backend::{config::BackendConfig, wizard::get_or_init_autoconfig},
|
||||
backend::config::BackendConfig,
|
||||
ui::{prompt, THEME},
|
||||
wizard_log, wizard_prompt,
|
||||
};
|
||||
|
@ -32,8 +32,11 @@ const KEYRING: &str = "Ask my password, then save it in my system's global keyri
|
|||
const RAW: &str = "Ask my password, then save it in the configuration file (not safe)";
|
||||
const CMD: &str = "Ask me a shell command that exposes my password";
|
||||
|
||||
pub(crate) async fn configure(account_name: &str, email: &str) -> Result<BackendConfig> {
|
||||
let autoconfig = get_or_init_autoconfig(email).await;
|
||||
pub(crate) async fn configure(
|
||||
account_name: &str,
|
||||
email: &str,
|
||||
autoconfig: Option<&AutoConfig>,
|
||||
) -> Result<BackendConfig> {
|
||||
let autoconfig_oauth2 = autoconfig.and_then(|c| c.oauth2());
|
||||
let autoconfig_server = autoconfig.and_then(|c| {
|
||||
c.email_provider()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::Result;
|
||||
use autoconfig::config::{AuthenticationType, SecurityType, ServerType};
|
||||
use autoconfig::config::{AuthenticationType, Config as AutoConfig, SecurityType, ServerType};
|
||||
use dialoguer::{Confirm, Input, Password, Select};
|
||||
use email::{
|
||||
account::config::{
|
||||
|
@ -12,7 +12,7 @@ use oauth::v2_0::{AuthorizationCodeGrant, Client};
|
|||
use secret::Secret;
|
||||
|
||||
use crate::{
|
||||
backend::{config::BackendConfig, wizard::get_or_init_autoconfig},
|
||||
backend::config::BackendConfig,
|
||||
ui::{prompt, THEME},
|
||||
wizard_log, wizard_prompt,
|
||||
};
|
||||
|
@ -32,8 +32,11 @@ const KEYRING: &str = "Ask my password, then save it in my system's global keyri
|
|||
const RAW: &str = "Ask my password, then save it in the configuration file (not safe)";
|
||||
const CMD: &str = "Ask me a shell command that exposes my password";
|
||||
|
||||
pub(crate) async fn configure(account_name: &str, email: &str) -> Result<BackendConfig> {
|
||||
let autoconfig = get_or_init_autoconfig(email).await;
|
||||
pub(crate) async fn configure(
|
||||
account_name: &str,
|
||||
email: &str,
|
||||
autoconfig: Option<&AutoConfig>,
|
||||
) -> Result<BackendConfig> {
|
||||
let autoconfig_oauth2 = autoconfig.and_then(|c| c.oauth2());
|
||||
let autoconfig_server = autoconfig.and_then(|c| {
|
||||
c.email_provider()
|
||||
|
@ -80,9 +83,9 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Backend
|
|||
.and_then(|s| s.port())
|
||||
.map(ToOwned::to_owned)
|
||||
.unwrap_or_else(|| match &autoconfig_encryption {
|
||||
SmtpEncryptionKind::Tls => 993,
|
||||
SmtpEncryptionKind::StartTls => 143,
|
||||
SmtpEncryptionKind::None => 143,
|
||||
SmtpEncryptionKind::Tls => 465,
|
||||
SmtpEncryptionKind::StartTls => 587,
|
||||
SmtpEncryptionKind::None => 25,
|
||||
});
|
||||
|
||||
let (encryption, default_port) = match encryption_idx {
|
||||
|
|
Loading…
Reference in a new issue