mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-22 11:00:19 +00:00
fix config and oauth2
This commit is contained in:
parent
c54ada730b
commit
ea9c28b9d7
9 changed files with 453 additions and 177 deletions
|
@ -12,17 +12,17 @@ use crate::{config::wizard::THEME, maildir, sendmail};
|
||||||
use super::{config::BackendConfig, BackendKind};
|
use super::{config::BackendConfig, BackendKind};
|
||||||
|
|
||||||
const DEFAULT_BACKEND_KINDS: &[BackendKind] = &[
|
const DEFAULT_BACKEND_KINDS: &[BackendKind] = &[
|
||||||
BackendKind::Maildir,
|
|
||||||
#[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
BackendKind::Imap,
|
BackendKind::Imap,
|
||||||
|
BackendKind::Maildir,
|
||||||
#[cfg(feature = "notmuch-backend")]
|
#[cfg(feature = "notmuch-backend")]
|
||||||
BackendKind::Notmuch,
|
BackendKind::Notmuch,
|
||||||
];
|
];
|
||||||
|
|
||||||
const SEND_MESSAGE_BACKEND_KINDS: &[BackendKind] = &[
|
const SEND_MESSAGE_BACKEND_KINDS: &[BackendKind] = &[
|
||||||
BackendKind::Sendmail,
|
|
||||||
#[cfg(feature = "smtp-sender")]
|
#[cfg(feature = "smtp-sender")]
|
||||||
BackendKind::Smtp,
|
BackendKind::Smtp,
|
||||||
|
BackendKind::Sendmail,
|
||||||
];
|
];
|
||||||
|
|
||||||
pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Option<BackendConfig>> {
|
pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Option<BackendConfig>> {
|
||||||
|
@ -52,7 +52,7 @@ pub(crate) async fn configure_sender(
|
||||||
email: &str,
|
email: &str,
|
||||||
) -> Result<Option<BackendConfig>> {
|
) -> Result<Option<BackendConfig>> {
|
||||||
let kind = Select::with_theme(&*THEME)
|
let kind = Select::with_theme(&*THEME)
|
||||||
.with_prompt("Default email backend")
|
.with_prompt("Backend for sending messages")
|
||||||
.items(SEND_MESSAGE_BACKEND_KINDS)
|
.items(SEND_MESSAGE_BACKEND_KINDS)
|
||||||
.default(0)
|
.default(0)
|
||||||
.interact_opt()?
|
.interact_opt()?
|
||||||
|
|
|
@ -44,11 +44,19 @@ pub struct TomlConfig {
|
||||||
pub email_listing_datetime_fmt: Option<String>,
|
pub email_listing_datetime_fmt: Option<String>,
|
||||||
pub email_listing_datetime_local_tz: Option<bool>,
|
pub email_listing_datetime_local_tz: Option<bool>,
|
||||||
pub email_reading_headers: Option<Vec<String>>,
|
pub email_reading_headers: Option<Vec<String>>,
|
||||||
#[serde(default, with = "OptionEmailTextPlainFormatDef")]
|
#[serde(
|
||||||
|
default,
|
||||||
|
with = "OptionEmailTextPlainFormatDef",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
pub email_reading_format: Option<EmailTextPlainFormat>,
|
pub email_reading_format: Option<EmailTextPlainFormat>,
|
||||||
pub email_writing_headers: Option<Vec<String>>,
|
pub email_writing_headers: Option<Vec<String>>,
|
||||||
pub email_sending_save_copy: Option<bool>,
|
pub email_sending_save_copy: Option<bool>,
|
||||||
#[serde(default, with = "OptionEmailHooksDef")]
|
#[serde(
|
||||||
|
default,
|
||||||
|
with = "OptionEmailHooksDef",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
pub email_hooks: Option<EmailHooks>,
|
pub email_hooks: Option<EmailHooks>,
|
||||||
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
@ -78,7 +86,7 @@ impl TomlConfig {
|
||||||
|
|
||||||
let confirm = Confirm::new()
|
let confirm = Confirm::new()
|
||||||
.with_prompt(wizard_prompt!(
|
.with_prompt(wizard_prompt!(
|
||||||
"Would you like to create it with the wizard?"
|
"Would you like to create one with the wizard?"
|
||||||
))
|
))
|
||||||
.default(true)
|
.default(true)
|
||||||
.interact_opt()?
|
.interact_opt()?
|
||||||
|
@ -88,7 +96,7 @@ impl TomlConfig {
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
wizard::configure().await
|
wizard::configure(path).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read and parse the TOML configuration from default paths.
|
/// Read and parse the TOML configuration from default paths.
|
||||||
|
|
|
@ -61,27 +61,38 @@ pub enum CmdDef {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "Option<Cmd>", from = "OptionCmd")]
|
#[serde(remote = "Option<Cmd>", from = "OptionCmd", into = "OptionCmd")]
|
||||||
pub struct OptionCmdDef;
|
pub struct OptionCmdDef;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
pub struct OptionCmd {
|
||||||
pub enum OptionCmd {
|
#[serde(default, skip)]
|
||||||
#[default]
|
is_some: bool,
|
||||||
#[serde(skip_serializing)]
|
#[serde(flatten, with = "CmdDef")]
|
||||||
None,
|
inner: Cmd,
|
||||||
#[serde(with = "SingleCmdDef")]
|
|
||||||
SingleCmd(SingleCmd),
|
|
||||||
#[serde(with = "PipelineDef")]
|
|
||||||
Pipeline(Pipeline),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OptionCmd> for Option<Cmd> {
|
impl From<OptionCmd> for Option<Cmd> {
|
||||||
fn from(cmd: OptionCmd) -> Option<Cmd> {
|
fn from(cmd: OptionCmd) -> Option<Cmd> {
|
||||||
match cmd {
|
if cmd.is_some {
|
||||||
OptionCmd::None => None,
|
Some(cmd.inner)
|
||||||
OptionCmd::SingleCmd(cmd) => Some(Cmd::SingleCmd(cmd)),
|
} else {
|
||||||
OptionCmd::Pipeline(pipeline) => Some(Cmd::Pipeline(pipeline)),
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<OptionCmd> for Option<Cmd> {
|
||||||
|
fn into(self) -> OptionCmd {
|
||||||
|
match self {
|
||||||
|
Some(cmd) => OptionCmd {
|
||||||
|
is_some: true,
|
||||||
|
inner: cmd,
|
||||||
|
},
|
||||||
|
None => OptionCmd {
|
||||||
|
is_some: false,
|
||||||
|
inner: Default::default(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +119,11 @@ pub enum OAuth2MethodDef {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "Option<ImapConfig>", from = "OptionImapConfig")]
|
#[serde(
|
||||||
|
remote = "Option<ImapConfig>",
|
||||||
|
from = "OptionImapConfig",
|
||||||
|
into = "OptionImapConfig"
|
||||||
|
)]
|
||||||
pub struct OptionImapConfigDef;
|
pub struct OptionImapConfigDef;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
@ -129,6 +144,21 @@ impl From<OptionImapConfig> for Option<ImapConfig> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Into<OptionImapConfig> for Option<ImapConfig> {
|
||||||
|
fn into(self) -> OptionImapConfig {
|
||||||
|
match self {
|
||||||
|
Some(config) => OptionImapConfig {
|
||||||
|
is_none: false,
|
||||||
|
inner: config,
|
||||||
|
},
|
||||||
|
None => OptionImapConfig {
|
||||||
|
is_none: true,
|
||||||
|
inner: Default::default(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "ImapConfig", rename_all = "kebab-case")]
|
#[serde(remote = "ImapConfig", rename_all = "kebab-case")]
|
||||||
|
@ -226,23 +256,42 @@ pub enum ImapOAuth2ScopesDef {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "Option<MaildirConfig>", from = "OptionMaildirConfig")]
|
#[serde(
|
||||||
|
remote = "Option<MaildirConfig>",
|
||||||
|
from = "OptionMaildirConfig",
|
||||||
|
into = "OptionMaildirConfig"
|
||||||
|
)]
|
||||||
pub struct OptionMaildirConfigDef;
|
pub struct OptionMaildirConfigDef;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
pub struct OptionMaildirConfig {
|
||||||
pub enum OptionMaildirConfig {
|
#[serde(default, skip)]
|
||||||
#[default]
|
is_none: bool,
|
||||||
#[serde(skip_serializing)]
|
#[serde(flatten, with = "MaildirConfigDef")]
|
||||||
None,
|
inner: MaildirConfig,
|
||||||
Some(#[serde(with = "MaildirConfigDef")] MaildirConfig),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OptionMaildirConfig> for Option<MaildirConfig> {
|
impl From<OptionMaildirConfig> for Option<MaildirConfig> {
|
||||||
fn from(config: OptionMaildirConfig) -> Option<MaildirConfig> {
|
fn from(config: OptionMaildirConfig) -> Option<MaildirConfig> {
|
||||||
match config {
|
if config.is_none {
|
||||||
OptionMaildirConfig::None => None,
|
None
|
||||||
OptionMaildirConfig::Some(config) => Some(config),
|
} else {
|
||||||
|
Some(config.inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<OptionMaildirConfig> for Option<MaildirConfig> {
|
||||||
|
fn into(self) -> OptionMaildirConfig {
|
||||||
|
match self {
|
||||||
|
Some(config) => OptionMaildirConfig {
|
||||||
|
is_none: false,
|
||||||
|
inner: config,
|
||||||
|
},
|
||||||
|
None => OptionMaildirConfig {
|
||||||
|
is_none: true,
|
||||||
|
inner: Default::default(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,25 +305,45 @@ pub struct MaildirConfigDef {
|
||||||
|
|
||||||
#[cfg(feature = "notmuch-backend")]
|
#[cfg(feature = "notmuch-backend")]
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "Option<NotmuchConfig>", from = "OptionNotmuchConfig")]
|
#[serde(
|
||||||
|
remote = "Option<NotmuchConfig>",
|
||||||
|
from = "OptionNotmuchConfig",
|
||||||
|
into = "OptionNotmuchConfig"
|
||||||
|
)]
|
||||||
pub struct OptionNotmuchConfigDef;
|
pub struct OptionNotmuchConfigDef;
|
||||||
|
|
||||||
#[cfg(feature = "notmuch-backend")]
|
#[cfg(feature = "notmuch-backend")]
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
pub struct OptionNotmuchConfig {
|
||||||
pub enum OptionNotmuchConfig {
|
#[serde(default, skip)]
|
||||||
#[default]
|
is_none: bool,
|
||||||
#[serde(skip_serializing)]
|
#[serde(flatten, with = "NotmuchConfigDef")]
|
||||||
None,
|
inner: NotmuchConfig,
|
||||||
Some(#[serde(with = "NotmuchConfigDef")] NotmuchConfig),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "notmuch-backend")]
|
#[cfg(feature = "notmuch-backend")]
|
||||||
impl From<OptionNotmuchConfig> for Option<NotmuchConfig> {
|
impl From<OptionNotmuchConfig> for Option<NotmuchConfig> {
|
||||||
fn from(config: OptionNotmuchConfig) -> Option<NotmuchConfig> {
|
fn from(config: OptionNotmuchConfig) -> Option<NotmuchConfig> {
|
||||||
match config {
|
if config.is_none {
|
||||||
OptionNotmuchConfig::None => None,
|
None
|
||||||
OptionNotmuchConfig::Some(config) => Some(config),
|
} else {
|
||||||
|
Some(config.inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "notmuch-backend")]
|
||||||
|
impl Into<OptionNotmuchConfig> for Option<NotmuchConfig> {
|
||||||
|
fn into(self) -> OptionNotmuchConfig {
|
||||||
|
match self {
|
||||||
|
Some(config) => OptionNotmuchConfig {
|
||||||
|
is_none: false,
|
||||||
|
inner: config,
|
||||||
|
},
|
||||||
|
None => OptionNotmuchConfig {
|
||||||
|
is_none: true,
|
||||||
|
inner: Default::default(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,28 +359,40 @@ pub struct NotmuchConfigDef {
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(
|
#[serde(
|
||||||
remote = "Option<EmailTextPlainFormat>",
|
remote = "Option<EmailTextPlainFormat>",
|
||||||
from = "OptionEmailTextPlainFormat"
|
from = "OptionEmailTextPlainFormat",
|
||||||
|
into = "OptionEmailTextPlainFormat"
|
||||||
)]
|
)]
|
||||||
pub struct OptionEmailTextPlainFormatDef;
|
pub struct OptionEmailTextPlainFormatDef;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
pub struct OptionEmailTextPlainFormat {
|
||||||
pub enum OptionEmailTextPlainFormat {
|
#[serde(default, skip)]
|
||||||
#[serde(skip_serializing)]
|
is_none: bool,
|
||||||
None,
|
#[serde(flatten, with = "EmailTextPlainFormatDef")]
|
||||||
#[default]
|
inner: EmailTextPlainFormat,
|
||||||
Auto,
|
|
||||||
Flowed,
|
|
||||||
Fixed(usize),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OptionEmailTextPlainFormat> for Option<EmailTextPlainFormat> {
|
impl From<OptionEmailTextPlainFormat> for Option<EmailTextPlainFormat> {
|
||||||
fn from(fmt: OptionEmailTextPlainFormat) -> Option<EmailTextPlainFormat> {
|
fn from(fmt: OptionEmailTextPlainFormat) -> Option<EmailTextPlainFormat> {
|
||||||
match fmt {
|
if fmt.is_none {
|
||||||
OptionEmailTextPlainFormat::None => None,
|
None
|
||||||
OptionEmailTextPlainFormat::Auto => Some(EmailTextPlainFormat::Auto),
|
} else {
|
||||||
OptionEmailTextPlainFormat::Flowed => Some(EmailTextPlainFormat::Flowed),
|
Some(fmt.inner)
|
||||||
OptionEmailTextPlainFormat::Fixed(size) => Some(EmailTextPlainFormat::Fixed(size)),
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<OptionEmailTextPlainFormat> for Option<EmailTextPlainFormat> {
|
||||||
|
fn into(self) -> OptionEmailTextPlainFormat {
|
||||||
|
match self {
|
||||||
|
Some(config) => OptionEmailTextPlainFormat {
|
||||||
|
is_none: false,
|
||||||
|
inner: config,
|
||||||
|
},
|
||||||
|
None => OptionEmailTextPlainFormat {
|
||||||
|
is_none: true,
|
||||||
|
inner: Default::default(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -331,7 +412,11 @@ pub enum EmailTextPlainFormatDef {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "Option<SmtpConfig>", from = "OptionSmtpConfig")]
|
#[serde(
|
||||||
|
remote = "Option<SmtpConfig>",
|
||||||
|
from = "OptionSmtpConfig",
|
||||||
|
into = "OptionSmtpConfig"
|
||||||
|
)]
|
||||||
pub struct OptionSmtpConfigDef;
|
pub struct OptionSmtpConfigDef;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
@ -352,6 +437,21 @@ impl From<OptionSmtpConfig> for Option<SmtpConfig> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Into<OptionSmtpConfig> for Option<SmtpConfig> {
|
||||||
|
fn into(self) -> OptionSmtpConfig {
|
||||||
|
match self {
|
||||||
|
Some(config) => OptionSmtpConfig {
|
||||||
|
is_none: false,
|
||||||
|
inner: config,
|
||||||
|
},
|
||||||
|
None => OptionSmtpConfig {
|
||||||
|
is_none: true,
|
||||||
|
inner: Default::default(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "smtp-sender")]
|
#[cfg(feature = "smtp-sender")]
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "SmtpConfig")]
|
#[serde(remote = "SmtpConfig")]
|
||||||
|
@ -434,23 +534,42 @@ pub enum SmtpOAuth2ScopesDef {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "Option<SendmailConfig>", from = "OptionSendmailConfig")]
|
#[serde(
|
||||||
|
remote = "Option<SendmailConfig>",
|
||||||
|
from = "OptionSendmailConfig",
|
||||||
|
into = "OptionSendmailConfig"
|
||||||
|
)]
|
||||||
pub struct OptionSendmailConfigDef;
|
pub struct OptionSendmailConfigDef;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
pub struct OptionSendmailConfig {
|
||||||
pub enum OptionSendmailConfig {
|
#[serde(default, skip)]
|
||||||
#[default]
|
is_none: bool,
|
||||||
#[serde(skip_serializing)]
|
#[serde(flatten, with = "SendmailConfigDef")]
|
||||||
None,
|
inner: SendmailConfig,
|
||||||
Some(#[serde(with = "SendmailConfigDef")] SendmailConfig),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OptionSendmailConfig> for Option<SendmailConfig> {
|
impl From<OptionSendmailConfig> for Option<SendmailConfig> {
|
||||||
fn from(config: OptionSendmailConfig) -> Option<SendmailConfig> {
|
fn from(config: OptionSendmailConfig) -> Option<SendmailConfig> {
|
||||||
match config {
|
if config.is_none {
|
||||||
OptionSendmailConfig::None => None,
|
None
|
||||||
OptionSendmailConfig::Some(config) => Some(config),
|
} else {
|
||||||
|
Some(config.inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<OptionSendmailConfig> for Option<SendmailConfig> {
|
||||||
|
fn into(self) -> OptionSendmailConfig {
|
||||||
|
match self {
|
||||||
|
Some(config) => OptionSendmailConfig {
|
||||||
|
is_none: false,
|
||||||
|
inner: config,
|
||||||
|
},
|
||||||
|
None => OptionSendmailConfig {
|
||||||
|
is_none: true,
|
||||||
|
inner: Default::default(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -467,23 +586,46 @@ fn sendmail_default_cmd() -> Cmd {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(remote = "Option<EmailHooks>", from = "OptionEmailHooks")]
|
#[serde(
|
||||||
|
remote = "Option<EmailHooks>",
|
||||||
|
from = "OptionEmailHooks",
|
||||||
|
into = "OptionEmailHooks"
|
||||||
|
)]
|
||||||
pub struct OptionEmailHooksDef;
|
pub struct OptionEmailHooksDef;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
pub struct OptionEmailHooks {
|
||||||
pub enum OptionEmailHooks {
|
#[serde(default, skip)]
|
||||||
#[default]
|
is_none: bool,
|
||||||
#[serde(skip_serializing)]
|
#[serde(
|
||||||
None,
|
flatten,
|
||||||
Some(#[serde(with = "EmailHooksDef")] EmailHooks),
|
skip_serializing_if = "EmailHooks::is_empty",
|
||||||
|
with = "EmailHooksDef"
|
||||||
|
)]
|
||||||
|
inner: EmailHooks,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OptionEmailHooks> for Option<EmailHooks> {
|
impl From<OptionEmailHooks> for Option<EmailHooks> {
|
||||||
fn from(fmt: OptionEmailHooks) -> Option<EmailHooks> {
|
fn from(hooks: OptionEmailHooks) -> Option<EmailHooks> {
|
||||||
match fmt {
|
if hooks.is_none {
|
||||||
OptionEmailHooks::None => None,
|
None
|
||||||
OptionEmailHooks::Some(hooks) => Some(hooks),
|
} else {
|
||||||
|
Some(hooks.inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<OptionEmailHooks> for Option<EmailHooks> {
|
||||||
|
fn into(self) -> OptionEmailHooks {
|
||||||
|
match self {
|
||||||
|
Some(hooks) => OptionEmailHooks {
|
||||||
|
is_none: false,
|
||||||
|
inner: hooks,
|
||||||
|
},
|
||||||
|
None => OptionEmailHooks {
|
||||||
|
is_none: true,
|
||||||
|
inner: Default::default(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -501,24 +643,44 @@ pub struct EmailHooksDef {
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(
|
#[serde(
|
||||||
remote = "Option<FolderSyncStrategy>",
|
remote = "Option<FolderSyncStrategy>",
|
||||||
from = "OptionFolderSyncStrategy"
|
from = "OptionFolderSyncStrategy",
|
||||||
|
into = "OptionFolderSyncStrategy"
|
||||||
)]
|
)]
|
||||||
pub struct OptionFolderSyncStrategyDef;
|
pub struct OptionFolderSyncStrategyDef;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
pub struct OptionFolderSyncStrategy {
|
||||||
pub enum OptionFolderSyncStrategy {
|
#[serde(default, skip)]
|
||||||
#[default]
|
is_some: bool,
|
||||||
#[serde(skip_serializing)]
|
#[serde(
|
||||||
None,
|
flatten,
|
||||||
Some(#[serde(with = "FolderSyncStrategyDef")] FolderSyncStrategy),
|
skip_serializing_if = "FolderSyncStrategy::is_default",
|
||||||
|
with = "FolderSyncStrategyDef"
|
||||||
|
)]
|
||||||
|
inner: FolderSyncStrategy,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OptionFolderSyncStrategy> for Option<FolderSyncStrategy> {
|
impl From<OptionFolderSyncStrategy> for Option<FolderSyncStrategy> {
|
||||||
fn from(config: OptionFolderSyncStrategy) -> Option<FolderSyncStrategy> {
|
fn from(option: OptionFolderSyncStrategy) -> Option<FolderSyncStrategy> {
|
||||||
match config {
|
if option.is_some {
|
||||||
OptionFolderSyncStrategy::None => None,
|
Some(option.inner)
|
||||||
OptionFolderSyncStrategy::Some(config) => Some(config),
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<OptionFolderSyncStrategy> for Option<FolderSyncStrategy> {
|
||||||
|
fn into(self) -> OptionFolderSyncStrategy {
|
||||||
|
match self {
|
||||||
|
Some(strategy) => OptionFolderSyncStrategy {
|
||||||
|
is_some: true,
|
||||||
|
inner: strategy,
|
||||||
|
},
|
||||||
|
None => OptionFolderSyncStrategy {
|
||||||
|
is_some: false,
|
||||||
|
inner: Default::default(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
use super::TomlConfig;
|
|
||||||
use crate::account;
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use dialoguer::{theme::ColorfulTheme, Confirm, Input, Password, Select};
|
use dialoguer::{theme::ColorfulTheme, Confirm, Input, Password, Select};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use shellexpand_utils::{shellexpand_path, try_shellexpand_path};
|
use shellexpand_utils::shellexpand_path;
|
||||||
use std::{env, fs, io, process};
|
use std::{fs, io, path::PathBuf, process};
|
||||||
|
use toml_edit::{Document, Item};
|
||||||
|
|
||||||
|
use crate::account;
|
||||||
|
|
||||||
|
use super::TomlConfig;
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! wizard_warn {
|
macro_rules! wizard_warn {
|
||||||
|
@ -31,7 +34,7 @@ macro_rules! wizard_log {
|
||||||
|
|
||||||
pub(crate) static THEME: Lazy<ColorfulTheme> = Lazy::new(ColorfulTheme::default);
|
pub(crate) static THEME: Lazy<ColorfulTheme> = Lazy::new(ColorfulTheme::default);
|
||||||
|
|
||||||
pub(crate) async fn configure() -> Result<TomlConfig> {
|
pub(crate) async fn configure(path: PathBuf) -> Result<TomlConfig> {
|
||||||
wizard_log!("Configuring your first account:");
|
wizard_log!("Configuring your first account:");
|
||||||
|
|
||||||
let mut config = TomlConfig::default();
|
let mut config = TomlConfig::default();
|
||||||
|
@ -89,25 +92,86 @@ pub(crate) async fn configure() -> Result<TomlConfig> {
|
||||||
.with_prompt(wizard_prompt!(
|
.with_prompt(wizard_prompt!(
|
||||||
"Where would you like to save your configuration?"
|
"Where would you like to save your configuration?"
|
||||||
))
|
))
|
||||||
.default(
|
.default(path.to_string_lossy().to_string())
|
||||||
dirs::config_dir()
|
|
||||||
.map(|p| p.join("himalaya").join("config.toml"))
|
|
||||||
.unwrap_or_else(|| env::temp_dir().join("himalaya").join("config.toml"))
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_string(),
|
|
||||||
)
|
|
||||||
.validate_with(|path: &String| try_shellexpand_path(path).map(|_| ()))
|
|
||||||
.interact()?;
|
.interact()?;
|
||||||
let path = shellexpand_path(&path);
|
let path = shellexpand_path(&path);
|
||||||
|
|
||||||
println!("Writing the configuration to {path:?}…");
|
println!("Writing the configuration to {path:?}…");
|
||||||
|
|
||||||
|
let mut doc = toml::to_string(&config)?.parse::<Document>()?;
|
||||||
|
|
||||||
|
doc.iter_mut().for_each(|(_, item)| {
|
||||||
|
set_table_dotted(item, "folder-aliases");
|
||||||
|
set_table_dotted(item, "sync-folders-strategy");
|
||||||
|
|
||||||
|
set_table_dotted(item, "folder");
|
||||||
|
get_table_mut(item, "folder").map(|item| {
|
||||||
|
set_tables_dotted(item, ["add", "list", "expunge", "purge", "delete"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
set_table_dotted(item, "envelope");
|
||||||
|
get_table_mut(item, "envelope").map(|item| {
|
||||||
|
set_tables_dotted(item, ["list", "get"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
set_table_dotted(item, "flag");
|
||||||
|
get_table_mut(item, "flag").map(|item| {
|
||||||
|
set_tables_dotted(item, ["add", "set", "remove"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
set_table_dotted(item, "message");
|
||||||
|
get_table_mut(item, "message").map(|item| {
|
||||||
|
set_tables_dotted(
|
||||||
|
item,
|
||||||
|
["add", "send", "peek", "get", "copy", "move", "delete"],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
set_table_dotted(item, "maildir");
|
||||||
|
#[cfg(feature = "imap-backend")]
|
||||||
|
{
|
||||||
|
set_table_dotted(item, "imap");
|
||||||
|
get_table_mut(item, "imap").map(|item| {
|
||||||
|
set_tables_dotted(item, ["passwd", "oauth2"]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#[cfg(feature = "notmuch-backend")]
|
||||||
|
set_table_dotted(item, "notmuch");
|
||||||
|
set_table_dotted(item, "sendmail");
|
||||||
|
#[cfg(feature = "smtp-sender")]
|
||||||
|
{
|
||||||
|
set_table_dotted(item, "smtp");
|
||||||
|
get_table_mut(item, "smtp").map(|item| {
|
||||||
|
set_tables_dotted(item, ["passwd", "oauth2"]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "pgp")]
|
||||||
|
set_table_dotted(item, "pgp");
|
||||||
|
});
|
||||||
|
|
||||||
fs::create_dir_all(path.parent().unwrap_or(&path))?;
|
fs::create_dir_all(path.parent().unwrap_or(&path))?;
|
||||||
fs::write(path, toml::to_string(&config)?)?;
|
fs::write(path, doc.to_string())?;
|
||||||
|
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_table_mut<'a>(item: &'a mut Item, key: &'a str) -> Option<&'a mut Item> {
|
||||||
|
item.get_mut(key).filter(|item| item.is_table())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_table_dotted(item: &mut Item, key: &str) {
|
||||||
|
get_table_mut(item, key)
|
||||||
|
.and_then(|item| item.as_table_mut())
|
||||||
|
.map(|table| table.set_dotted(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_tables_dotted<'a>(item: &'a mut Item, keys: impl IntoIterator<Item = &'a str>) {
|
||||||
|
for key in keys {
|
||||||
|
set_table_dotted(item, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn prompt_passwd(prompt: &str) -> io::Result<String> {
|
pub(crate) fn prompt_passwd(prompt: &str) -> io::Result<String> {
|
||||||
Password::with_theme(&*THEME)
|
Password::with_theme(&*THEME)
|
||||||
.with_prompt(prompt)
|
.with_prompt(prompt)
|
||||||
|
|
|
@ -31,7 +31,7 @@ use crate::{
|
||||||
|
|
||||||
/// Represents all existing kind of account config.
|
/// Represents all existing kind of account config.
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
#[serde(tag = "backend", rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct TomlAccountConfig {
|
pub struct TomlAccountConfig {
|
||||||
pub default: Option<bool>,
|
pub default: Option<bool>,
|
||||||
|
|
||||||
|
@ -48,16 +48,28 @@ pub struct TomlAccountConfig {
|
||||||
pub email_listing_datetime_fmt: Option<String>,
|
pub email_listing_datetime_fmt: Option<String>,
|
||||||
pub email_listing_datetime_local_tz: Option<bool>,
|
pub email_listing_datetime_local_tz: Option<bool>,
|
||||||
pub email_reading_headers: Option<Vec<String>>,
|
pub email_reading_headers: Option<Vec<String>>,
|
||||||
#[serde(default, with = "OptionEmailTextPlainFormatDef")]
|
#[serde(
|
||||||
|
default,
|
||||||
|
with = "OptionEmailTextPlainFormatDef",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
pub email_reading_format: Option<EmailTextPlainFormat>,
|
pub email_reading_format: Option<EmailTextPlainFormat>,
|
||||||
pub email_writing_headers: Option<Vec<String>>,
|
pub email_writing_headers: Option<Vec<String>>,
|
||||||
pub email_sending_save_copy: Option<bool>,
|
pub email_sending_save_copy: Option<bool>,
|
||||||
#[serde(default, with = "OptionEmailHooksDef")]
|
#[serde(
|
||||||
|
default,
|
||||||
|
with = "OptionEmailHooksDef",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
pub email_hooks: Option<EmailHooks>,
|
pub email_hooks: Option<EmailHooks>,
|
||||||
|
|
||||||
pub sync: Option<bool>,
|
pub sync: Option<bool>,
|
||||||
pub sync_dir: Option<PathBuf>,
|
pub sync_dir: Option<PathBuf>,
|
||||||
#[serde(default, with = "OptionFolderSyncStrategyDef")]
|
#[serde(
|
||||||
|
default,
|
||||||
|
with = "OptionFolderSyncStrategyDef",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
pub sync_folders_strategy: Option<FolderSyncStrategy>,
|
pub sync_folders_strategy: Option<FolderSyncStrategy>,
|
||||||
|
|
||||||
pub backend: Option<BackendKind>,
|
pub backend: Option<BackendKind>,
|
||||||
|
@ -68,25 +80,49 @@ pub struct TomlAccountConfig {
|
||||||
pub message: Option<MessageConfig>,
|
pub message: Option<MessageConfig>,
|
||||||
|
|
||||||
#[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
#[serde(default, with = "OptionImapConfigDef")]
|
#[serde(
|
||||||
|
default,
|
||||||
|
with = "OptionImapConfigDef",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
pub imap: Option<ImapConfig>,
|
pub imap: Option<ImapConfig>,
|
||||||
|
|
||||||
#[serde(default, with = "OptionMaildirConfigDef")]
|
#[serde(
|
||||||
|
default,
|
||||||
|
with = "OptionMaildirConfigDef",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
pub maildir: Option<MaildirConfig>,
|
pub maildir: Option<MaildirConfig>,
|
||||||
|
|
||||||
#[cfg(feature = "notmuch-backend")]
|
#[cfg(feature = "notmuch-backend")]
|
||||||
#[serde(default, with = "OptionNotmuchConfigDef")]
|
#[serde(
|
||||||
|
default,
|
||||||
|
with = "OptionNotmuchConfigDef",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
pub notmuch: Option<NotmuchConfig>,
|
pub notmuch: Option<NotmuchConfig>,
|
||||||
|
|
||||||
#[cfg(feature = "smtp-sender")]
|
#[cfg(feature = "smtp-sender")]
|
||||||
#[serde(default, with = "OptionSmtpConfigDef")]
|
#[serde(
|
||||||
|
default,
|
||||||
|
with = "OptionSmtpConfigDef",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
pub smtp: Option<SmtpConfig>,
|
pub smtp: Option<SmtpConfig>,
|
||||||
|
|
||||||
#[serde(default, with = "OptionSendmailConfigDef")]
|
#[serde(
|
||||||
|
default,
|
||||||
|
with = "OptionSendmailConfigDef",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
pub sendmail: Option<SendmailConfig>,
|
pub sendmail: Option<SendmailConfig>,
|
||||||
|
|
||||||
#[cfg(feature = "pgp")]
|
#[cfg(feature = "pgp")]
|
||||||
#[serde(default, with = "OptionPgpConfigDef")]
|
#[serde(
|
||||||
|
default,
|
||||||
|
with = "OptionPgpConfigDef",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
pub pgp: Option<PgpConfig>,
|
pub pgp: Option<PgpConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//!
|
//!
|
||||||
//! This module gathers all account actions triggered by the CLI.
|
//! This module gathers all account actions triggered by the CLI.
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::Result;
|
||||||
use email::account::{
|
use email::account::{
|
||||||
sync::{AccountSyncBuilder, AccountSyncProgressEvent},
|
sync::{AccountSyncBuilder, AccountSyncProgressEvent},
|
||||||
AccountConfig,
|
AccountConfig,
|
||||||
|
@ -12,7 +12,7 @@ use email::imap::ImapAuthConfig;
|
||||||
#[cfg(feature = "smtp-sender")]
|
#[cfg(feature = "smtp-sender")]
|
||||||
use email::smtp::SmtpAuthConfig;
|
use email::smtp::SmtpAuthConfig;
|
||||||
use indicatif::{MultiProgress, ProgressBar, ProgressFinish, ProgressStyle};
|
use indicatif::{MultiProgress, ProgressBar, ProgressFinish, ProgressStyle};
|
||||||
use log::{info, trace, warn};
|
use log::{debug, info, trace, warn};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::{collections::HashMap, sync::Mutex};
|
use std::{collections::HashMap, sync::Mutex};
|
||||||
|
|
||||||
|
@ -26,6 +26,8 @@ use crate::{
|
||||||
Accounts,
|
Accounts,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::TomlAccountConfig;
|
||||||
|
|
||||||
const MAIN_PROGRESS_STYLE: Lazy<ProgressStyle> = Lazy::new(|| {
|
const MAIN_PROGRESS_STYLE: Lazy<ProgressStyle> = Lazy::new(|| {
|
||||||
ProgressStyle::with_template(" {spinner:.dim} {msg:.dim}\n {wide_bar:.cyan/blue} \n").unwrap()
|
ProgressStyle::with_template(" {spinner:.dim} {msg:.dim}\n {wide_bar:.cyan/blue} \n").unwrap()
|
||||||
});
|
});
|
||||||
|
@ -42,71 +44,75 @@ const SUB_PROGRESS_DONE_STYLE: Lazy<ProgressStyle> = Lazy::new(|| {
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Configure the current selected account
|
/// Configure the current selected account
|
||||||
pub async fn configure(config: &AccountConfig, reset: bool) -> Result<()> {
|
pub async fn configure(config: &TomlAccountConfig, reset: bool) -> Result<()> {
|
||||||
info!("entering the configure account handler");
|
info!("entering the configure account handler");
|
||||||
|
|
||||||
// if reset {
|
if reset {
|
||||||
// #[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
// if let BackendConfig::Imap(imap_config) = &config.backend {
|
if let Some(ref config) = config.imap {
|
||||||
// let reset = match &imap_config.auth {
|
let reset = match &config.auth {
|
||||||
// ImapAuthConfig::Passwd(passwd) => passwd.reset(),
|
ImapAuthConfig::Passwd(config) => config.reset(),
|
||||||
// ImapAuthConfig::OAuth2(oauth2) => oauth2.reset(),
|
ImapAuthConfig::OAuth2(config) => config.reset(),
|
||||||
// };
|
};
|
||||||
// if let Err(err) = reset {
|
if let Err(err) = reset {
|
||||||
// warn!("error while resetting imap secrets, skipping it");
|
warn!("error while resetting imap secrets: {err}");
|
||||||
// warn!("{err}");
|
debug!("error while resetting imap secrets: {err:?}");
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// #[cfg(feature = "smtp-sender")]
|
#[cfg(feature = "smtp-sender")]
|
||||||
// if let SenderConfig::Smtp(smtp_config) = &config.sender {
|
if let Some(ref config) = config.smtp {
|
||||||
// let reset = match &smtp_config.auth {
|
let reset = match &config.auth {
|
||||||
// SmtpAuthConfig::Passwd(passwd) => passwd.reset(),
|
SmtpAuthConfig::Passwd(config) => config.reset(),
|
||||||
// SmtpAuthConfig::OAuth2(oauth2) => oauth2.reset(),
|
SmtpAuthConfig::OAuth2(config) => config.reset(),
|
||||||
// };
|
};
|
||||||
// if let Err(err) = reset {
|
if let Err(err) = reset {
|
||||||
// warn!("error while resetting smtp secrets, skipping it");
|
warn!("error while resetting smtp secrets: {err}");
|
||||||
// warn!("{err}");
|
debug!("error while resetting smtp secrets: {err:?}");
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// #[cfg(feature = "pgp")]
|
#[cfg(feature = "pgp")]
|
||||||
// config.pgp.reset().await?;
|
if let Some(ref config) = config.pgp {
|
||||||
// }
|
config.pgp.reset().await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// #[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
// if let BackendConfig::Imap(imap_config) = &config.backend {
|
if let Some(ref config) = config.imap {
|
||||||
// match &imap_config.auth {
|
match &config.auth {
|
||||||
// ImapAuthConfig::Passwd(passwd) => {
|
ImapAuthConfig::Passwd(config) => {
|
||||||
// passwd.configure(|| prompt_passwd("IMAP password")).await
|
config.configure(|| prompt_passwd("IMAP password")).await
|
||||||
// }
|
}
|
||||||
// ImapAuthConfig::OAuth2(oauth2) => {
|
ImapAuthConfig::OAuth2(config) => {
|
||||||
// oauth2
|
config
|
||||||
// .configure(|| prompt_secret("IMAP OAuth 2.0 client secret"))
|
.configure(|| prompt_secret("IMAP OAuth 2.0 client secret"))
|
||||||
// .await
|
.await
|
||||||
// }
|
}
|
||||||
// }?;
|
}?;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// #[cfg(feature = "smtp-sender")]
|
#[cfg(feature = "smtp-sender")]
|
||||||
// if let SenderConfig::Smtp(smtp_config) = &config.sender {
|
if let Some(ref config) = config.smtp {
|
||||||
// match &smtp_config.auth {
|
match &config.auth {
|
||||||
// SmtpAuthConfig::Passwd(passwd) => {
|
SmtpAuthConfig::Passwd(config) => {
|
||||||
// passwd.configure(|| prompt_passwd("SMTP password")).await
|
config.configure(|| prompt_passwd("SMTP password")).await
|
||||||
// }
|
}
|
||||||
// SmtpAuthConfig::OAuth2(oauth2) => {
|
SmtpAuthConfig::OAuth2(config) => {
|
||||||
// oauth2
|
config
|
||||||
// .configure(|| prompt_secret("SMTP OAuth 2.0 client secret"))
|
.configure(|| prompt_secret("SMTP OAuth 2.0 client secret"))
|
||||||
// .await
|
.await
|
||||||
// }
|
}
|
||||||
// }?;
|
}?;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// #[cfg(feature = "pgp")]
|
#[cfg(feature = "pgp")]
|
||||||
// config
|
if let Some(ref config) = config.pgp {
|
||||||
// .pgp
|
config
|
||||||
// .configure(&config.email, || prompt_passwd("PGP secret key password"))
|
.pgp
|
||||||
// .await?;
|
.configure(&config.email, || prompt_passwd("PGP secret key password"))
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Account successfully {}configured!",
|
"Account successfully {}configured!",
|
||||||
|
|
|
@ -10,7 +10,7 @@ pub struct MessageConfig {
|
||||||
pub peek: Option<MessagePeekConfig>,
|
pub peek: Option<MessagePeekConfig>,
|
||||||
pub get: Option<MessageGetConfig>,
|
pub get: Option<MessageGetConfig>,
|
||||||
pub copy: Option<MessageCopyConfig>,
|
pub copy: Option<MessageCopyConfig>,
|
||||||
#[serde(rename = "move")]
|
#[serde(default, rename = "move", skip_serializing_if = "Option::is_none")]
|
||||||
pub move_: Option<MessageMoveConfig>,
|
pub move_: Option<MessageMoveConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Backend
|
||||||
ImapAuthConfig::Passwd(config)
|
ImapAuthConfig::Passwd(config)
|
||||||
}
|
}
|
||||||
Some(idx) if AUTH_MECHANISMS[idx] == OAUTH2 => {
|
Some(idx) if AUTH_MECHANISMS[idx] == OAUTH2 => {
|
||||||
let mut config = OAuth2Config::default();
|
let mut config = OAuth2Config::new()?;
|
||||||
|
|
||||||
let method = Select::with_theme(&*THEME)
|
let method = Select::with_theme(&*THEME)
|
||||||
.with_prompt("IMAP OAuth 2.0 mechanism")
|
.with_prompt("IMAP OAuth 2.0 mechanism")
|
||||||
|
|
|
@ -131,10 +131,10 @@ async fn main() -> Result<()> {
|
||||||
return account::handlers::sync(&mut printer, sync_builder, dry_run).await;
|
return account::handlers::sync(&mut printer, sync_builder, dry_run).await;
|
||||||
}
|
}
|
||||||
Some(account::args::Cmd::Configure(reset)) => {
|
Some(account::args::Cmd::Configure(reset)) => {
|
||||||
let (_, account_config) = toml_config
|
let (toml_account_config, _) = toml_config
|
||||||
.clone()
|
.clone()
|
||||||
.into_account_configs(some_account_name, disable_cache)?;
|
.into_account_configs(some_account_name, disable_cache)?;
|
||||||
return account::handlers::configure(&account_config, reset).await;
|
return account::handlers::configure(&toml_account_config, reset).await;
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue