mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-24 20:10:23 +00:00
set up imap oauth2 config
This commit is contained in:
parent
e271ca4293
commit
21f67bc7f5
9 changed files with 1244 additions and 61 deletions
1197
Cargo.lock
generated
1197
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -48,7 +48,8 @@ dialoguer = "0.10.2"
|
||||||
email_address = "0.2.4"
|
email_address = "0.2.4"
|
||||||
env_logger = "0.8"
|
env_logger = "0.8"
|
||||||
erased-serde = "0.3"
|
erased-serde = "0.3"
|
||||||
pimalaya-email = "0.7.1"
|
# pimalaya-email = "0.7.1"
|
||||||
|
pimalaya-email = { path = "/home/soywod/sourcehut/pimalaya/email" }
|
||||||
indicatif = "0.17"
|
indicatif = "0.17"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
once_cell = "1.16.0"
|
once_cell = "1.16.0"
|
||||||
|
|
17
flake.lock
17
flake.lock
|
@ -21,6 +21,22 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1673956053,
|
||||||
|
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
|
@ -98,6 +114,7 @@
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"fenix": "fenix",
|
"fenix": "fenix",
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"gitignore": "gitignore",
|
"gitignore": "gitignore",
|
||||||
"naersk": "naersk",
|
"naersk": "naersk",
|
||||||
|
|
|
@ -16,9 +16,13 @@
|
||||||
url = "github:nix-community/naersk";
|
url = "github:nix-community/naersk";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
flake-compat = {
|
||||||
|
url = "github:edolstra/flake-compat";
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, flake-utils, gitignore, fenix, naersk }:
|
outputs = { self, nixpkgs, flake-utils, gitignore, fenix, naersk, ... }:
|
||||||
let
|
let
|
||||||
inherit (gitignore.lib) gitignoreSource;
|
inherit (gitignore.lib) gitignoreSource;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use pimalaya_email::{
|
use pimalaya_email::{
|
||||||
folder::sync::Strategy as SyncFoldersStrategy, EmailHooks, EmailSender, EmailTextPlainFormat,
|
folder::sync::Strategy as SyncFoldersStrategy, EmailHooks, EmailSender, EmailTextPlainFormat,
|
||||||
MaildirConfig, SendmailConfig, SmtpConfig,
|
ImapAuthConfig, MaildirConfig, OAuth2Config, OAuth2Method, OAuth2Scopes, SendmailConfig,
|
||||||
|
SmtpConfig,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashSet, path::PathBuf};
|
use std::{collections::HashSet, path::PathBuf};
|
||||||
|
@ -46,8 +47,8 @@ pub struct ImapConfigDef {
|
||||||
pub insecure: Option<bool>,
|
pub insecure: Option<bool>,
|
||||||
#[serde(rename = "imap-login")]
|
#[serde(rename = "imap-login")]
|
||||||
pub login: String,
|
pub login: String,
|
||||||
#[serde(rename = "imap-passwd-cmd")]
|
#[serde(flatten, with = "ImapAuthConfigDef")]
|
||||||
pub passwd_cmd: String,
|
pub auth: ImapAuthConfig,
|
||||||
#[serde(rename = "imap-notify-cmd")]
|
#[serde(rename = "imap-notify-cmd")]
|
||||||
pub notify_cmd: Option<String>,
|
pub notify_cmd: Option<String>,
|
||||||
#[serde(rename = "imap-notify-query")]
|
#[serde(rename = "imap-notify-query")]
|
||||||
|
@ -56,6 +57,48 @@ pub struct ImapConfigDef {
|
||||||
pub watch_cmds: Option<Vec<String>>,
|
pub watch_cmds: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
|
#[serde(remote = "ImapAuthConfig", rename_all = "kebab-case")]
|
||||||
|
pub enum ImapAuthConfigDef {
|
||||||
|
#[default]
|
||||||
|
None,
|
||||||
|
#[serde(rename = "imap-passwd")]
|
||||||
|
Passwd(String),
|
||||||
|
#[serde(rename = "imap-passwd-cmd")]
|
||||||
|
PasswdCmd(String),
|
||||||
|
#[serde(rename = "imap-oauth2", with = "OAuth2ConfigDef")]
|
||||||
|
OAuth2(OAuth2Config),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
|
#[serde(remote = "OAuth2Config", rename_all = "kebab-case")]
|
||||||
|
pub struct OAuth2ConfigDef {
|
||||||
|
#[serde(with = "OAuth2MethodDef")]
|
||||||
|
pub method: OAuth2Method,
|
||||||
|
pub client_id: String,
|
||||||
|
pub client_secret: String,
|
||||||
|
pub auth_url: String,
|
||||||
|
pub token_url: String,
|
||||||
|
#[serde(flatten, with = "OAuth2ScopesDef")]
|
||||||
|
pub scopes: OAuth2Scopes,
|
||||||
|
#[serde(default)]
|
||||||
|
pub pkce: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
|
#[serde(remote = "OAuth2Method", rename_all = "lowercase")]
|
||||||
|
pub enum OAuth2MethodDef {
|
||||||
|
XOAuth2,
|
||||||
|
OAuthBearer,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
|
#[serde(remote = "OAuth2Scopes", rename_all = "kebab-case")]
|
||||||
|
pub enum OAuth2ScopesDef {
|
||||||
|
Scope(String),
|
||||||
|
Scopes(Vec<String>),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
#[serde(remote = "MaildirConfig", rename_all = "kebab-case")]
|
#[serde(remote = "MaildirConfig", rename_all = "kebab-case")]
|
||||||
pub struct MaildirConfigDef {
|
pub struct MaildirConfigDef {
|
||||||
|
|
|
@ -46,10 +46,11 @@ pub(crate) fn configure(base: DeserializedBaseAccountConfig) -> Result<Deseriali
|
||||||
.default(base.email.clone())
|
.default(base.email.clone())
|
||||||
.interact()?;
|
.interact()?;
|
||||||
|
|
||||||
backend.passwd_cmd = Input::with_theme(&*THEME)
|
// FIXME: add all variants: password, password command and oauth2
|
||||||
.with_prompt("What shell command should we run to get your password?")
|
// backend.passwd_cmd = Input::with_theme(&*THEME)
|
||||||
.default(format!("pass show {}", &base.email))
|
// .with_prompt("What shell command should we run to get your password?")
|
||||||
.interact()?;
|
// .default(format!("pass show {}", &base.email))
|
||||||
|
// .interact()?;
|
||||||
|
|
||||||
Ok(DeserializedAccountConfig::Imap(
|
Ok(DeserializedAccountConfig::Imap(
|
||||||
DeserializedImapAccountConfig { base, backend },
|
DeserializedImapAccountConfig { base, backend },
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::{folder, ui::table};
|
||||||
const ARG_ACCOUNT: &str = "account";
|
const ARG_ACCOUNT: &str = "account";
|
||||||
const ARG_DRY_RUN: &str = "dry-run";
|
const ARG_DRY_RUN: &str = "dry-run";
|
||||||
const CMD_ACCOUNTS: &str = "accounts";
|
const CMD_ACCOUNTS: &str = "accounts";
|
||||||
|
const CMD_CONFIGURE: &str = "configure";
|
||||||
const CMD_LIST: &str = "list";
|
const CMD_LIST: &str = "list";
|
||||||
const CMD_SYNC: &str = "sync";
|
const CMD_SYNC: &str = "sync";
|
||||||
|
|
||||||
|
@ -23,6 +24,8 @@ pub enum Cmd {
|
||||||
List(table::args::MaxTableWidth),
|
List(table::args::MaxTableWidth),
|
||||||
/// Represents the sync account command.
|
/// Represents the sync account command.
|
||||||
Sync(Option<SyncFoldersStrategy>, DryRun),
|
Sync(Option<SyncFoldersStrategy>, DryRun),
|
||||||
|
/// Configure the current selected account.
|
||||||
|
Configure,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the account command matcher.
|
/// Represents the account command matcher.
|
||||||
|
@ -51,6 +54,9 @@ pub fn matches(m: &ArgMatches) -> Result<Option<Cmd>> {
|
||||||
info!("list accounts subcommand matched");
|
info!("list accounts subcommand matched");
|
||||||
let max_table_width = table::args::parse_max_width(m);
|
let max_table_width = table::args::parse_max_width(m);
|
||||||
Some(Cmd::List(max_table_width))
|
Some(Cmd::List(max_table_width))
|
||||||
|
} else if let Some(_) = m.subcommand_matches(CMD_CONFIGURE) {
|
||||||
|
info!("configure account subcommand matched");
|
||||||
|
Some(Cmd::Configure)
|
||||||
} else {
|
} else {
|
||||||
info!("no account subcommand matched, falling back to subcommand list");
|
info!("no account subcommand matched, falling back to subcommand list");
|
||||||
Some(Cmd::List(None))
|
Some(Cmd::List(None))
|
||||||
|
@ -80,6 +86,9 @@ pub fn subcmd() -> Command {
|
||||||
"Synchronize all folders except the given ones",
|
"Synchronize all folders except the given ones",
|
||||||
))
|
))
|
||||||
.arg(dry_run()),
|
.arg(dry_run()),
|
||||||
|
Command::new(CMD_CONFIGURE)
|
||||||
|
.about("Configure the current selected account")
|
||||||
|
.aliases(["config", "conf", "cfg"]),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@ use anyhow::Result;
|
||||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||||
use log::{info, trace};
|
use log::{info, trace};
|
||||||
use pimalaya_email::{
|
use pimalaya_email::{
|
||||||
folder::sync::Strategy as SyncFoldersStrategy, AccountConfig, Backend, BackendSyncBuilder,
|
folder::sync::Strategy as SyncFoldersStrategy, AccountConfig, Backend, BackendConfig,
|
||||||
BackendSyncProgressEvent,
|
BackendSyncBuilder, BackendSyncProgressEvent,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -16,6 +16,14 @@ use crate::{
|
||||||
Accounts,
|
Accounts,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Configure the current selected account
|
||||||
|
pub fn configure(account_config: &AccountConfig, backend_config: &BackendConfig) -> Result<()> {
|
||||||
|
info!("entering the configure account handler");
|
||||||
|
backend_config.configure(&account_config.name)?;
|
||||||
|
println!("Account {} configured!", account_config.name);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Lists all accounts.
|
/// Lists all accounts.
|
||||||
pub fn list<'a, P: Printer>(
|
pub fn list<'a, P: Printer>(
|
||||||
max_width: Option<usize>,
|
max_width: Option<usize>,
|
||||||
|
|
|
@ -137,6 +137,9 @@ fn main() -> Result<()> {
|
||||||
backend.close()?;
|
backend.close()?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
Some(account::args::Cmd::Configure) => {
|
||||||
|
return account::handlers::configure(&account_config, &backend_config);
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue