mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-21 18:40:19 +00:00
use tokio async runtime
last fixes before merge
This commit is contained in:
parent
f8ca248bce
commit
cac8280c8c
31 changed files with 538 additions and 332 deletions
31
Cargo.lock
generated
31
Cargo.lock
generated
|
@ -1218,6 +1218,7 @@ name = "himalaya"
|
|||
version = "0.8.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"atty",
|
||||
"chrono",
|
||||
"clap",
|
||||
|
@ -2199,12 +2200,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pimalaya-email"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8375dc804686e9e03a8b6f87d80b9038b5a734efb4b77f81b90b07b8ac1d4499"
|
||||
version = "0.13.0"
|
||||
source = "git+https://git.sr.ht/~soywod/pimalaya#5250a4c906228da7f2d1ca1d58468a760c69c720"
|
||||
dependencies = [
|
||||
"advisory-lock",
|
||||
"ammonia",
|
||||
"async-trait",
|
||||
"chrono",
|
||||
"convert_case",
|
||||
"dirs",
|
||||
|
@ -2244,10 +2245,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pimalaya-email-tpl"
|
||||
version = "0.2.3"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a838dd91468bf79997ead555d6a5b93f066e363259925ec931d49591b1ebb79"
|
||||
checksum = "c536455f778ed7aa0948b755281e8e6a61650a857a3f610ff7e60b097a681838"
|
||||
dependencies = [
|
||||
"async-recursion",
|
||||
"chumsky 0.9.0",
|
||||
"log",
|
||||
"mail-builder",
|
||||
|
@ -2285,19 +2287,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pimalaya-process"
|
||||
version = "0.0.2"
|
||||
version = "0.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d8d2853bf2f0efbe397ce22bb4e6d53a7464f6dcc0abe7e2936f6f4e8e2726a"
|
||||
checksum = "1a9d1e1ab6334d4e4d06613cd65f3fed34e5d2d7b1488f3d1a0d2fdffdba5d1c"
|
||||
dependencies = [
|
||||
"log",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pimalaya-secret"
|
||||
version = "0.0.2"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9338dc84e5ec9fc25f3a36d82ed68ffe4888ad728ca1aa42228e27648ddff01f"
|
||||
checksum = "0f975cafe977327bb215cf71e953dd1f1bfa45d3cf4ab5e806493d917e0a0cd1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"pimalaya-keyring",
|
||||
|
@ -2925,6 +2928,15 @@ dependencies = [
|
|||
"dirs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.10"
|
||||
|
@ -3181,6 +3193,7 @@ dependencies = [
|
|||
"mio",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.42.0",
|
||||
|
|
|
@ -25,6 +25,7 @@ notmuch-backend = ["pimalaya-email/notmuch-backend"]
|
|||
smtp-sender = ["pimalaya-email/smtp-sender"]
|
||||
|
||||
[dev-dependencies]
|
||||
async-trait = "0.1"
|
||||
tempfile = "3.3"
|
||||
|
||||
[dependencies]
|
||||
|
@ -44,17 +45,17 @@ indicatif = "0.17"
|
|||
log = "0.4"
|
||||
md5 = "0.7.0"
|
||||
once_cell = "1.16.0"
|
||||
pimalaya-email = { version = "=0.11.0", default-features = false }
|
||||
pimalaya-email = { git = "https://git.sr.ht/~soywod/pimalaya", default-features = false }
|
||||
pimalaya-keyring = "=0.0.4"
|
||||
pimalaya-oauth2 = "=0.0.3"
|
||||
pimalaya-process = "=0.0.2"
|
||||
pimalaya-secret = "=0.0.2"
|
||||
pimalaya-process = "=0.0.5"
|
||||
pimalaya-secret = "=0.0.4"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
shellexpand = "2.1"
|
||||
termcolor = "1.1"
|
||||
terminal_size = "0.1"
|
||||
tokio = { version = "1.23", default-features = false, features = ["macros"] }
|
||||
tokio = { version = "1.23", default-features = false, features = ["macros", "rt-multi-thread"] }
|
||||
toml = "0.7.4"
|
||||
toml_edit = "0.19.8"
|
||||
unicode-width = "0.1"
|
||||
|
|
6
src/cache/id_mapper.rs
vendored
6
src/cache/id_mapper.rs
vendored
|
@ -1,10 +1,10 @@
|
|||
use anyhow::{anyhow, Context, Result};
|
||||
use log::{debug, trace};
|
||||
#[cfg(feature = "imap-backend")]
|
||||
use pimalaya_email::ImapBackend;
|
||||
use pimalaya_email::backend::ImapBackend;
|
||||
#[cfg(feature = "notmuch-backend")]
|
||||
use pimalaya_email::NotmuchBackend;
|
||||
use pimalaya_email::{Backend, MaildirBackend};
|
||||
use pimalaya_email::backend::NotmuchBackend;
|
||||
use pimalaya_email::backend::{Backend, MaildirBackend};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
const ID_MAPPER_DB_FILE_NAME: &str = ".id-mapper.sqlite";
|
||||
|
|
|
@ -7,7 +7,10 @@ use anyhow::{anyhow, Context, Result};
|
|||
use dialoguer::Confirm;
|
||||
use dirs::{config_dir, home_dir};
|
||||
use log::{debug, trace};
|
||||
use pimalaya_email::{AccountConfig, EmailHooks, EmailTextPlainFormat};
|
||||
use pimalaya_email::{
|
||||
account::AccountConfig,
|
||||
email::{EmailHooks, EmailTextPlainFormat},
|
||||
};
|
||||
use pimalaya_process::Cmd;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, fs, path::PathBuf, process};
|
||||
|
@ -158,16 +161,18 @@ impl DeserializedConfig {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pimalaya_email::{
|
||||
BackendConfig, MaildirConfig, PasswdConfig, SenderConfig, SendmailConfig,
|
||||
account::PasswdConfig,
|
||||
backend::{BackendConfig, MaildirConfig},
|
||||
sender::{SenderConfig, SendmailConfig},
|
||||
};
|
||||
use pimalaya_secret::Secret;
|
||||
|
||||
#[cfg(feature = "notmuch-backend")]
|
||||
use pimalaya_email::NotmuchConfig;
|
||||
use pimalaya_email::backend::NotmuchConfig;
|
||||
#[cfg(feature = "imap-backend")]
|
||||
use pimalaya_email::{ImapAuthConfig, ImapConfig};
|
||||
use pimalaya_email::backend::{ImapAuthConfig, ImapConfig};
|
||||
#[cfg(feature = "smtp-sender")]
|
||||
use pimalaya_email::{SmtpAuthConfig, SmtpConfig};
|
||||
use pimalaya_email::sender::{SmtpAuthConfig, SmtpConfig};
|
||||
|
||||
use std::io::Write;
|
||||
use tempfile::NamedTempFile;
|
||||
|
@ -453,7 +458,7 @@ mod tests {
|
|||
#[cfg(feature = "smtp-sender")]
|
||||
#[test]
|
||||
fn account_smtp_sender_minimum_config() {
|
||||
use pimalaya_email::SenderConfig;
|
||||
use pimalaya_email::sender::SenderConfig;
|
||||
|
||||
let config = make_config(
|
||||
"[account]
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
#[cfg(feature = "imap-backend")]
|
||||
use pimalaya_email::backend::{ImapAuthConfig, ImapConfig};
|
||||
#[cfg(feature = "smtp-sender")]
|
||||
use pimalaya_email::sender::{SmtpAuthConfig, SmtpConfig};
|
||||
#[cfg(feature = "notmuch-backend")]
|
||||
use pimalaya_email::NotmuchConfig;
|
||||
use pimalaya_email::{
|
||||
BackendConfig, EmailHooks, EmailTextPlainFormat, FolderSyncStrategy, MaildirConfig,
|
||||
OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig, SenderConfig, SendmailConfig,
|
||||
account::{OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig},
|
||||
backend::{BackendConfig, MaildirConfig},
|
||||
email::{EmailHooks, EmailTextPlainFormat},
|
||||
folder::sync::FolderSyncStrategy,
|
||||
sender::{SenderConfig, SendmailConfig},
|
||||
};
|
||||
#[cfg(feature = "imap-backend")]
|
||||
use pimalaya_email::{ImapAuthConfig, ImapConfig};
|
||||
#[cfg(feature = "smtp-sender")]
|
||||
use pimalaya_email::{SmtpAuthConfig, SmtpConfig};
|
||||
use pimalaya_keyring::Entry;
|
||||
use pimalaya_process::{Cmd, Pipeline, SingleCmd};
|
||||
use pimalaya_secret::Secret;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! accounts from the config file.
|
||||
|
||||
use anyhow::Result;
|
||||
use pimalaya_email::BackendConfig;
|
||||
use pimalaya_email::backend::BackendConfig;
|
||||
use serde::Serialize;
|
||||
use std::{collections::hash_map::Iter, ops::Deref};
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use anyhow::Result;
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||
use log::info;
|
||||
use pimalaya_email::FolderSyncStrategy;
|
||||
use pimalaya_email::folder::sync::FolderSyncStrategy;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::{folder, ui::table};
|
||||
|
|
|
@ -4,12 +4,15 @@
|
|||
//! account in the accounts section of the user configuration file.
|
||||
|
||||
#[cfg(feature = "imap-backend")]
|
||||
use pimalaya_email::ImapAuthConfig;
|
||||
use pimalaya_email::backend::ImapAuthConfig;
|
||||
#[cfg(feature = "smtp-sender")]
|
||||
use pimalaya_email::SmtpAuthConfig;
|
||||
use pimalaya_email::sender::SmtpAuthConfig;
|
||||
use pimalaya_email::{
|
||||
AccountConfig, BackendConfig, EmailHooks, EmailTextPlainFormat, FolderSyncStrategy,
|
||||
SenderConfig,
|
||||
account::AccountConfig,
|
||||
backend::BackendConfig,
|
||||
email::{EmailHooks, EmailTextPlainFormat},
|
||||
folder::sync::FolderSyncStrategy,
|
||||
sender::SenderConfig,
|
||||
};
|
||||
use pimalaya_process::Cmd;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
|
@ -7,11 +7,16 @@ use indicatif::{MultiProgress, ProgressBar, ProgressFinish, ProgressStyle};
|
|||
use log::{info, trace, warn};
|
||||
use once_cell::sync::Lazy;
|
||||
#[cfg(feature = "imap-backend")]
|
||||
use pimalaya_email::ImapAuthConfig;
|
||||
use pimalaya_email::backend::ImapAuthConfig;
|
||||
#[cfg(feature = "smtp-sender")]
|
||||
use pimalaya_email::SmtpAuthConfig;
|
||||
use pimalaya_email::sender::SmtpAuthConfig;
|
||||
use pimalaya_email::{
|
||||
AccountConfig, BackendConfig, BackendSyncBuilder, BackendSyncProgressEvent, SenderConfig,
|
||||
account::{
|
||||
sync::{AccountSyncBuilder, AccountSyncProgressEvent},
|
||||
AccountConfig,
|
||||
},
|
||||
backend::BackendConfig,
|
||||
sender::SenderConfig,
|
||||
};
|
||||
use std::{collections::HashMap, sync::Mutex};
|
||||
|
||||
|
@ -40,7 +45,7 @@ const SUB_PROGRESS_DONE_STYLE: Lazy<ProgressStyle> = Lazy::new(|| {
|
|||
});
|
||||
|
||||
/// Configure the current selected account
|
||||
pub fn configure(config: &AccountConfig, reset: bool) -> Result<()> {
|
||||
pub async fn configure(config: &AccountConfig, reset: bool) -> Result<()> {
|
||||
info!("entering the configure account handler");
|
||||
|
||||
if reset {
|
||||
|
@ -72,9 +77,13 @@ pub fn configure(config: &AccountConfig, reset: bool) -> Result<()> {
|
|||
#[cfg(feature = "imap-backend")]
|
||||
if let BackendConfig::Imap(imap_config) = &config.backend {
|
||||
match &imap_config.auth {
|
||||
ImapAuthConfig::Passwd(passwd) => passwd.configure(|| prompt_passwd("IMAP password")),
|
||||
ImapAuthConfig::Passwd(passwd) => {
|
||||
passwd.configure(|| prompt_passwd("IMAP password")).await
|
||||
}
|
||||
ImapAuthConfig::OAuth2(oauth2) => {
|
||||
oauth2.configure(|| prompt_secret("IMAP OAuth 2.0 client secret"))
|
||||
oauth2
|
||||
.configure(|| prompt_secret("IMAP OAuth 2.0 client secret"))
|
||||
.await
|
||||
}
|
||||
}?;
|
||||
}
|
||||
|
@ -82,9 +91,13 @@ pub fn configure(config: &AccountConfig, reset: bool) -> Result<()> {
|
|||
#[cfg(feature = "smtp-sender")]
|
||||
if let SenderConfig::Smtp(smtp_config) = &config.sender {
|
||||
match &smtp_config.auth {
|
||||
SmtpAuthConfig::Passwd(passwd) => passwd.configure(|| prompt_passwd("SMTP password")),
|
||||
SmtpAuthConfig::Passwd(passwd) => {
|
||||
passwd.configure(|| prompt_passwd("SMTP password")).await
|
||||
}
|
||||
SmtpAuthConfig::OAuth2(oauth2) => {
|
||||
oauth2.configure(|| prompt_secret("SMTP OAuth 2.0 client secret"))
|
||||
oauth2
|
||||
.configure(|| prompt_secret("SMTP OAuth 2.0 client secret"))
|
||||
.await
|
||||
}
|
||||
}?;
|
||||
}
|
||||
|
@ -123,16 +136,16 @@ pub fn list<'a, P: Printer>(
|
|||
|
||||
/// Synchronizes the account defined using argument `-a|--account`. If
|
||||
/// no account given, synchronizes the default one.
|
||||
pub fn sync<'a, P: Printer>(
|
||||
pub async fn sync<P: Printer>(
|
||||
printer: &mut P,
|
||||
sync_builder: BackendSyncBuilder<'a>,
|
||||
sync_builder: AccountSyncBuilder,
|
||||
dry_run: bool,
|
||||
) -> Result<()> {
|
||||
info!("entering the sync accounts handler");
|
||||
trace!("dry run: {dry_run}");
|
||||
|
||||
if dry_run {
|
||||
let report = sync_builder.sync()?;
|
||||
let report = sync_builder.sync().await?;
|
||||
let mut hunks_count = report.folders_patch.len();
|
||||
|
||||
if !report.folders_patch.is_empty() {
|
||||
|
@ -143,9 +156,9 @@ pub fn sync<'a, P: Printer>(
|
|||
printer.print_log("")?;
|
||||
}
|
||||
|
||||
if !report.envelopes_patch.is_empty() {
|
||||
if !report.emails_patch.is_empty() {
|
||||
printer.print_log("Envelopes patch:")?;
|
||||
for (hunk, _) in report.envelopes_patch {
|
||||
for (hunk, _) in report.emails_patch {
|
||||
hunks_count += 1;
|
||||
printer.print_log(format!(" - {hunk}"))?;
|
||||
}
|
||||
|
@ -156,7 +169,7 @@ pub fn sync<'a, P: Printer>(
|
|||
"Estimated patch length for account to be synchronized: {hunks_count}",
|
||||
))?;
|
||||
} else if printer.is_json() {
|
||||
sync_builder.sync()?;
|
||||
sync_builder.sync().await?;
|
||||
printer.print("Account successfully synchronized!")?;
|
||||
} else {
|
||||
let multi = MultiProgress::new();
|
||||
|
@ -172,7 +185,7 @@ pub fn sync<'a, P: Printer>(
|
|||
|
||||
let report = sync_builder
|
||||
.with_on_progress(move |evt| {
|
||||
use BackendSyncProgressEvent::*;
|
||||
use AccountSyncProgressEvent::*;
|
||||
Ok(match evt {
|
||||
ApplyFolderPatches(..) => {
|
||||
main_progress.inc(3);
|
||||
|
@ -223,7 +236,8 @@ pub fn sync<'a, P: Printer>(
|
|||
_ => (),
|
||||
})
|
||||
})
|
||||
.sync()?;
|
||||
.sync()
|
||||
.await?;
|
||||
|
||||
let folders_patch_err = report
|
||||
.folders_patch
|
||||
|
@ -246,7 +260,7 @@ pub fn sync<'a, P: Printer>(
|
|||
}
|
||||
|
||||
let envelopes_patch_err = report
|
||||
.envelopes_patch
|
||||
.emails_patch
|
||||
.iter()
|
||||
.filter_map(|(hunk, err)| err.as_ref().map(|err| (hunk, err)))
|
||||
.collect::<Vec<_>>();
|
||||
|
@ -258,7 +272,7 @@ pub fn sync<'a, P: Printer>(
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(err) = report.envelopes_cache_patch.1 {
|
||||
if let Some(err) = report.emails_cache_patch.1 {
|
||||
printer.print_log("")?;
|
||||
printer.print_log(format!(
|
||||
"Error occurred while applying the envelopes cache patch: {err}"
|
||||
|
@ -273,7 +287,7 @@ pub fn sync<'a, P: Printer>(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pimalaya_email::{AccountConfig, ImapConfig};
|
||||
use pimalaya_email::{account::AccountConfig, backend::ImapConfig};
|
||||
use std::{collections::HashMap, fmt::Debug, io};
|
||||
use termcolor::ColorSpec;
|
||||
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
//! This module gathers all IMAP handlers triggered by the CLI.
|
||||
|
||||
use anyhow::Result;
|
||||
use pimalaya_email::ImapBackend;
|
||||
use pimalaya_email::backend::ImapBackend;
|
||||
|
||||
pub fn notify(imap: &mut ImapBackend, folder: &str, keepalive: u64) -> Result<()> {
|
||||
imap.notify(keepalive, folder)?;
|
||||
pub async fn notify(imap: &mut ImapBackend, folder: &str, keepalive: u64) -> Result<()> {
|
||||
imap.notify(keepalive, folder).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn watch(imap: &mut ImapBackend, folder: &str, keepalive: u64) -> Result<()> {
|
||||
imap.watch(keepalive, folder)?;
|
||||
pub async fn watch(imap: &mut ImapBackend, folder: &str, keepalive: u64) -> Result<()> {
|
||||
imap.watch(keepalive, folder).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use anyhow::Result;
|
||||
use dialoguer::{Confirm, Input, Password, Select};
|
||||
use pimalaya_email::{
|
||||
BackendConfig, ImapAuthConfig, ImapConfig, OAuth2Config, OAuth2Method, OAuth2Scopes,
|
||||
PasswdConfig,
|
||||
account::{OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig},
|
||||
backend::{BackendConfig, ImapAuthConfig, ImapConfig},
|
||||
};
|
||||
use pimalaya_oauth2::{AuthorizationCodeGrant, Client};
|
||||
use pimalaya_secret::Secret;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use anyhow::Result;
|
||||
use dialoguer::Input;
|
||||
use dirs::home_dir;
|
||||
use pimalaya_email::{BackendConfig, MaildirConfig};
|
||||
use pimalaya_email::backend::{BackendConfig, MaildirConfig};
|
||||
|
||||
use crate::config::wizard::THEME;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use anyhow::Result;
|
||||
use dialoguer::Select;
|
||||
use pimalaya_email::BackendConfig;
|
||||
use pimalaya_email::backend::BackendConfig;
|
||||
|
||||
use crate::config::wizard::THEME;
|
||||
|
||||
|
|
|
@ -2,7 +2,10 @@ use anyhow::{anyhow, Context, Result};
|
|||
use atty::Stream;
|
||||
use log::{debug, trace};
|
||||
use pimalaya_email::{
|
||||
AccountConfig, Backend, Email, EmailBuilder, FilterParts, Flag, Flags, Sender,
|
||||
account::AccountConfig,
|
||||
backend::Backend,
|
||||
email::{template::FilterParts, Flag, Flags, Message, MessageBuilder},
|
||||
sender::Sender,
|
||||
};
|
||||
use std::{
|
||||
fs,
|
||||
|
@ -17,7 +20,7 @@ use crate::{
|
|||
Envelopes, IdMapper,
|
||||
};
|
||||
|
||||
pub fn attachments<P: Printer>(
|
||||
pub async fn attachments<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
|
@ -28,7 +31,7 @@ pub fn attachments<P: Printer>(
|
|||
let folder = config.folder_alias(folder)?;
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
let emails = backend.get_emails(&folder, ids.clone())?;
|
||||
let emails = backend.get_emails(&folder, ids.clone()).await?;
|
||||
let mut index = 0;
|
||||
|
||||
let mut emails_count = 0;
|
||||
|
@ -57,7 +60,7 @@ pub fn attachments<P: Printer>(
|
|||
let filename = attachment
|
||||
.filename
|
||||
.unwrap_or_else(|| Uuid::new_v4().to_string());
|
||||
let filepath = config.get_download_file_path(&filename)?;
|
||||
let filepath = config.download_fpath(&filename)?;
|
||||
printer.print_log(format!("Downloading {:?}…", filepath))?;
|
||||
fs::write(&filepath, &attachment.body).context("cannot download attachment")?;
|
||||
attachments_count = attachments_count + 1;
|
||||
|
@ -74,7 +77,7 @@ pub fn attachments<P: Printer>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn copy<P: Printer>(
|
||||
pub async fn copy<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
|
@ -87,11 +90,11 @@ pub fn copy<P: Printer>(
|
|||
let to_folder = config.folder_alias(to_folder)?;
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
backend.copy_emails(&from_folder, &to_folder, ids)?;
|
||||
backend.copy_emails(&from_folder, &to_folder, ids).await?;
|
||||
printer.print("Email(s) successfully copied!")
|
||||
}
|
||||
|
||||
pub fn delete<P: Printer>(
|
||||
pub async fn delete<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
|
@ -102,11 +105,11 @@ pub fn delete<P: Printer>(
|
|||
let folder = config.folder_alias(folder)?;
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
backend.delete_emails(&folder, ids)?;
|
||||
backend.delete_emails(&folder, ids).await?;
|
||||
printer.print("Email(s) successfully deleted!")
|
||||
}
|
||||
|
||||
pub fn forward<P: Printer>(
|
||||
pub async fn forward<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
|
@ -123,19 +126,21 @@ pub fn forward<P: Printer>(
|
|||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
|
||||
let tpl = backend
|
||||
.get_emails(&folder, ids)?
|
||||
.get_emails(&folder, ids)
|
||||
.await?
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("cannot find email {}", id))?
|
||||
.to_forward_tpl_builder(config)
|
||||
.some_headers(headers)
|
||||
.some_body(body)
|
||||
.build()?;
|
||||
.with_some_headers(headers)
|
||||
.with_some_body(body)
|
||||
.build()
|
||||
.await?;
|
||||
trace!("initial template: {}", *tpl);
|
||||
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl)?;
|
||||
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn list<P: Printer>(
|
||||
pub async fn list<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
|
@ -152,7 +157,7 @@ pub fn list<P: Printer>(
|
|||
let envelopes = Envelopes::from_backend(
|
||||
config,
|
||||
id_mapper,
|
||||
backend.list_envelopes(&folder, page_size, page)?,
|
||||
backend.list_envelopes(&folder, page_size, page).await?,
|
||||
)?;
|
||||
trace!("envelopes: {:?}", envelopes);
|
||||
|
||||
|
@ -168,14 +173,14 @@ pub fn list<P: Printer>(
|
|||
/// Parses and edits a message from a [mailto] URL string.
|
||||
///
|
||||
/// [mailto]: https://en.wikipedia.org/wiki/Mailto
|
||||
pub fn mailto<P: Printer>(
|
||||
pub async fn mailto<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
backend: &mut dyn Backend,
|
||||
sender: &mut dyn Sender,
|
||||
printer: &mut P,
|
||||
url: &Url,
|
||||
) -> Result<()> {
|
||||
let mut builder = EmailBuilder::new().to(url.path());
|
||||
let mut builder = MessageBuilder::new().to(url.path());
|
||||
|
||||
for (key, val) in url.query_pairs() {
|
||||
match key.to_lowercase().as_bytes() {
|
||||
|
@ -190,12 +195,13 @@ pub fn mailto<P: Printer>(
|
|||
let tpl = config
|
||||
.generate_tpl_interpreter()
|
||||
.show_only_headers(config.email_writing_headers())
|
||||
.interpret_msg_builder(builder)?;
|
||||
.interpret_msg_builder(builder)
|
||||
.await?;
|
||||
|
||||
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl)
|
||||
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl).await
|
||||
}
|
||||
|
||||
pub fn move_<P: Printer>(
|
||||
pub async fn move_<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
|
@ -208,11 +214,11 @@ pub fn move_<P: Printer>(
|
|||
let to_folder = config.folder_alias(to_folder)?;
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
backend.move_emails(&from_folder, &to_folder, ids)?;
|
||||
backend.move_emails(&from_folder, &to_folder, ids).await?;
|
||||
printer.print("Email(s) successfully moved!")
|
||||
}
|
||||
|
||||
pub fn read<P: Printer>(
|
||||
pub async fn read<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
|
@ -226,7 +232,7 @@ pub fn read<P: Printer>(
|
|||
let folder = config.folder_alias(folder)?;
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
let emails = backend.get_emails(&folder, ids)?;
|
||||
let emails = backend.get_emails(&folder, ids).await?;
|
||||
|
||||
let mut glue = "";
|
||||
let mut bodies = String::default();
|
||||
|
@ -245,7 +251,8 @@ pub fn read<P: Printer>(
|
|||
.hide_all_headers()
|
||||
.filter_parts(FilterParts::Only("text/html".into())),
|
||||
_ => tpl.show_additional_headers(&headers),
|
||||
})?
|
||||
})
|
||||
.await?
|
||||
.into();
|
||||
bodies.push_str(&tpl);
|
||||
}
|
||||
|
@ -256,7 +263,7 @@ pub fn read<P: Printer>(
|
|||
printer.print(bodies)
|
||||
}
|
||||
|
||||
pub fn reply<P: Printer>(
|
||||
pub async fn reply<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
|
@ -274,21 +281,25 @@ pub fn reply<P: Printer>(
|
|||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
|
||||
let tpl = backend
|
||||
.get_emails(&folder, ids)?
|
||||
.get_emails(&folder, ids)
|
||||
.await?
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("cannot find email {}", id))?
|
||||
.to_reply_tpl_builder(config)
|
||||
.some_headers(headers)
|
||||
.some_body(body)
|
||||
.reply_all(all)
|
||||
.build()?;
|
||||
.with_some_headers(headers)
|
||||
.with_some_body(body)
|
||||
.with_reply_all(all)
|
||||
.build()
|
||||
.await?;
|
||||
trace!("initial template: {}", *tpl);
|
||||
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl)?;
|
||||
backend.add_flags(&folder, vec![id], &Flags::from_iter([Flag::Answered]))?;
|
||||
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl).await?;
|
||||
backend
|
||||
.add_flags(&folder, vec![id], &Flags::from_iter([Flag::Answered]))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn save<P: Printer>(
|
||||
pub async fn save<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
|
@ -310,13 +321,15 @@ pub fn save<P: Printer>(
|
|||
.join("\r\n")
|
||||
};
|
||||
|
||||
let id = backend.add_email(&folder, raw_email.as_bytes(), &Flags::default())?;
|
||||
let id = backend
|
||||
.add_email(&folder, raw_email.as_bytes(), &Flags::default())
|
||||
.await?;
|
||||
id_mapper.create_alias(id)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn search<P: Printer>(
|
||||
pub async fn search<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
|
@ -332,7 +345,9 @@ pub fn search<P: Printer>(
|
|||
let envelopes = Envelopes::from_backend(
|
||||
config,
|
||||
id_mapper,
|
||||
backend.search_envelopes(&folder, &query, "", page_size, page)?,
|
||||
backend
|
||||
.search_envelopes(&folder, &query, "", page_size, page)
|
||||
.await?,
|
||||
)?;
|
||||
let opts = PrintTableOpts {
|
||||
format: &config.email_reading_format,
|
||||
|
@ -342,7 +357,7 @@ pub fn search<P: Printer>(
|
|||
printer.print_table(Box::new(envelopes), opts)
|
||||
}
|
||||
|
||||
pub fn sort<P: Printer>(
|
||||
pub async fn sort<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
|
@ -359,7 +374,9 @@ pub fn sort<P: Printer>(
|
|||
let envelopes = Envelopes::from_backend(
|
||||
config,
|
||||
id_mapper,
|
||||
backend.search_envelopes(&folder, &query, &sort, page_size, page)?,
|
||||
backend
|
||||
.search_envelopes(&folder, &query, &sort, page_size, page)
|
||||
.await?,
|
||||
)?;
|
||||
let opts = PrintTableOpts {
|
||||
format: &config.email_reading_format,
|
||||
|
@ -369,7 +386,7 @@ pub fn sort<P: Printer>(
|
|||
printer.print_table(Box::new(envelopes), opts)
|
||||
}
|
||||
|
||||
pub fn send<P: Printer>(
|
||||
pub async fn send<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut dyn Backend,
|
||||
|
@ -390,18 +407,20 @@ pub fn send<P: Printer>(
|
|||
.join("\r\n")
|
||||
};
|
||||
trace!("raw email: {:?}", raw_email);
|
||||
sender.send(raw_email.as_bytes())?;
|
||||
sender.send(raw_email.as_bytes()).await?;
|
||||
if config.email_sending_save_copy {
|
||||
backend.add_email(
|
||||
&folder,
|
||||
raw_email.as_bytes(),
|
||||
&Flags::from_iter([Flag::Seen]),
|
||||
)?;
|
||||
backend
|
||||
.add_email(
|
||||
&folder,
|
||||
raw_email.as_bytes(),
|
||||
&Flags::from_iter([Flag::Seen]),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write<P: Printer>(
|
||||
pub async fn write<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut dyn Backend,
|
||||
|
@ -409,11 +428,12 @@ pub fn write<P: Printer>(
|
|||
headers: Option<Vec<(&str, &str)>>,
|
||||
body: Option<&str>,
|
||||
) -> Result<()> {
|
||||
let tpl = Email::new_tpl_builder(config)
|
||||
.some_headers(headers)
|
||||
.some_body(body)
|
||||
.build()?;
|
||||
let tpl = Message::new_tpl_builder(config)
|
||||
.with_some_headers(headers)
|
||||
.with_some_body(body)
|
||||
.build()
|
||||
.await?;
|
||||
trace!("initial template: {}", *tpl);
|
||||
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl)?;
|
||||
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::Result;
|
||||
use pimalaya_email::AccountConfig;
|
||||
use pimalaya_email::account::AccountConfig;
|
||||
use serde::Serialize;
|
||||
use std::ops;
|
||||
|
||||
|
@ -17,7 +17,7 @@ impl Envelopes {
|
|||
pub fn from_backend(
|
||||
config: &AccountConfig,
|
||||
id_mapper: &IdMapper,
|
||||
envelopes: pimalaya_email::Envelopes,
|
||||
envelopes: pimalaya_email::email::Envelopes,
|
||||
) -> Result<Envelopes> {
|
||||
let envelopes = envelopes
|
||||
.iter()
|
||||
|
@ -58,10 +58,9 @@ impl PrintTable for Envelopes {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::env;
|
||||
|
||||
use chrono::DateTime;
|
||||
use pimalaya_email::AccountConfig;
|
||||
use pimalaya_email::account::AccountConfig;
|
||||
use std::env;
|
||||
|
||||
use crate::{Envelopes, IdMapper};
|
||||
|
||||
|
@ -70,10 +69,11 @@ mod tests {
|
|||
let config = AccountConfig::default();
|
||||
let id_mapper = IdMapper::Dummy;
|
||||
|
||||
let envelopes = pimalaya_email::Envelopes::from_iter([pimalaya_email::Envelope {
|
||||
date: DateTime::parse_from_rfc3339("2023-06-15T09:42:00+04:00").unwrap(),
|
||||
..Default::default()
|
||||
}]);
|
||||
let envelopes =
|
||||
pimalaya_email::email::Envelopes::from_iter([pimalaya_email::email::Envelope {
|
||||
date: DateTime::parse_from_rfc3339("2023-06-15T09:42:00+04:00").unwrap(),
|
||||
..Default::default()
|
||||
}]);
|
||||
let envelopes = Envelopes::from_backend(&config, &id_mapper, envelopes).unwrap();
|
||||
|
||||
let expected_date = "2023-06-15 09:42+04:00";
|
||||
|
@ -90,10 +90,11 @@ mod tests {
|
|||
..AccountConfig::default()
|
||||
};
|
||||
|
||||
let envelopes = pimalaya_email::Envelopes::from_iter([pimalaya_email::Envelope {
|
||||
date: DateTime::parse_from_rfc3339("2023-06-15T09:42:00+04:00").unwrap(),
|
||||
..Default::default()
|
||||
}]);
|
||||
let envelopes =
|
||||
pimalaya_email::email::Envelopes::from_iter([pimalaya_email::email::Envelope {
|
||||
date: DateTime::parse_from_rfc3339("2023-06-15T09:42:00+04:00").unwrap(),
|
||||
..Default::default()
|
||||
}]);
|
||||
let envelopes = Envelopes::from_backend(&config, &id_mapper, envelopes).unwrap();
|
||||
|
||||
let expected_date = "15/06/2023 09h42";
|
||||
|
@ -113,10 +114,11 @@ mod tests {
|
|||
..AccountConfig::default()
|
||||
};
|
||||
|
||||
let envelopes = pimalaya_email::Envelopes::from_iter([pimalaya_email::Envelope {
|
||||
date: DateTime::parse_from_rfc3339("2023-06-15T09:42:00+04:00").unwrap(),
|
||||
..Default::default()
|
||||
}]);
|
||||
let envelopes =
|
||||
pimalaya_email::email::Envelopes::from_iter([pimalaya_email::email::Envelope {
|
||||
date: DateTime::parse_from_rfc3339("2023-06-15T09:42:00+04:00").unwrap(),
|
||||
..Default::default()
|
||||
}]);
|
||||
let envelopes = Envelopes::from_backend(&config, &id_mapper, envelopes).unwrap();
|
||||
|
||||
let expected_date = "15/06/2023 05h42";
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
use anyhow::Result;
|
||||
use clap::{Arg, ArgMatches, Command};
|
||||
use log::{debug, info};
|
||||
use pimalaya_email::{Flag, Flags};
|
||||
use pimalaya_email::email::{Flag, Flags};
|
||||
|
||||
use crate::email;
|
||||
|
||||
|
|
|
@ -11,15 +11,16 @@ pub enum Flag {
|
|||
Custom(String),
|
||||
}
|
||||
|
||||
impl From<&pimalaya_email::Flag> for Flag {
|
||||
fn from(flag: &pimalaya_email::Flag) -> Self {
|
||||
impl From<&pimalaya_email::email::Flag> for Flag {
|
||||
fn from(flag: &pimalaya_email::email::Flag) -> Self {
|
||||
use pimalaya_email::email::Flag::*;
|
||||
match flag {
|
||||
pimalaya_email::Flag::Seen => Flag::Seen,
|
||||
pimalaya_email::Flag::Answered => Flag::Answered,
|
||||
pimalaya_email::Flag::Flagged => Flag::Flagged,
|
||||
pimalaya_email::Flag::Deleted => Flag::Deleted,
|
||||
pimalaya_email::Flag::Draft => Flag::Draft,
|
||||
pimalaya_email::Flag::Custom(flag) => Flag::Custom(flag.clone()),
|
||||
Seen => Flag::Seen,
|
||||
Answered => Flag::Answered,
|
||||
Flagged => Flag::Flagged,
|
||||
Deleted => Flag::Deleted,
|
||||
Draft => Flag::Draft,
|
||||
Custom(flag) => Flag::Custom(flag.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@ impl ops::Deref for Flags {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<pimalaya_email::Flags> for Flags {
|
||||
fn from(flags: pimalaya_email::Flags) -> Self {
|
||||
impl From<pimalaya_email::email::Flags> for Flags {
|
||||
fn from(flags: pimalaya_email::email::Flags) -> Self {
|
||||
Flags(flags.iter().map(Flag::from).collect())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use anyhow::Result;
|
||||
use pimalaya_email::{Backend, Flags};
|
||||
use pimalaya_email::{backend::Backend, email::Flags};
|
||||
|
||||
use crate::{printer::Printer, IdMapper};
|
||||
|
||||
pub fn add<P: Printer>(
|
||||
pub async fn add<P: Printer>(
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
|
@ -13,11 +13,11 @@ pub fn add<P: Printer>(
|
|||
) -> Result<()> {
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
backend.add_flags(folder, ids, flags)?;
|
||||
backend.add_flags(folder, ids, flags).await?;
|
||||
printer.print("Flag(s) successfully added!")
|
||||
}
|
||||
|
||||
pub fn set<P: Printer>(
|
||||
pub async fn set<P: Printer>(
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
|
@ -27,11 +27,11 @@ pub fn set<P: Printer>(
|
|||
) -> Result<()> {
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
backend.set_flags(folder, ids, flags)?;
|
||||
backend.set_flags(folder, ids, flags).await?;
|
||||
printer.print("Flag(s) successfully set!")
|
||||
}
|
||||
|
||||
pub fn remove<P: Printer>(
|
||||
pub async fn remove<P: Printer>(
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
|
@ -41,6 +41,6 @@ pub fn remove<P: Printer>(
|
|||
) -> Result<()> {
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
backend.remove_flags(folder, ids, flags)?;
|
||||
backend.remove_flags(folder, ids, flags).await?;
|
||||
printer.print("Flag(s) successfully removed!")
|
||||
}
|
||||
|
|
|
@ -4,15 +4,13 @@ use crate::ui::{Cell, Row, Table};
|
|||
|
||||
#[derive(Clone, Debug, Default, Serialize)]
|
||||
pub struct Folder {
|
||||
pub delim: String,
|
||||
pub name: String,
|
||||
pub desc: String,
|
||||
}
|
||||
|
||||
impl From<&pimalaya_email::Folder> for Folder {
|
||||
fn from(folder: &pimalaya_email::Folder) -> Self {
|
||||
impl From<&pimalaya_email::folder::Folder> for Folder {
|
||||
fn from(folder: &pimalaya_email::folder::Folder) -> Self {
|
||||
Folder {
|
||||
delim: folder.delim.clone(),
|
||||
name: folder.name.clone(),
|
||||
desc: folder.desc.clone(),
|
||||
}
|
||||
|
@ -22,14 +20,12 @@ impl From<&pimalaya_email::Folder> for Folder {
|
|||
impl Table for Folder {
|
||||
fn head() -> Row {
|
||||
Row::new()
|
||||
.cell(Cell::new("DELIM").bold().underline().white())
|
||||
.cell(Cell::new("NAME").bold().underline().white())
|
||||
.cell(Cell::new("DESC").bold().underline().white())
|
||||
}
|
||||
|
||||
fn row(&self) -> Row {
|
||||
Row::new()
|
||||
.cell(Cell::new(&self.delim).white())
|
||||
.cell(Cell::new(&self.name).blue())
|
||||
.cell(Cell::new(&self.desc).green())
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use std::ops;
|
||||
|
||||
use anyhow::Result;
|
||||
use serde::Serialize;
|
||||
use std::ops;
|
||||
|
||||
use crate::{
|
||||
printer::{PrintTable, PrintTableOpts, WriteColor},
|
||||
|
@ -20,8 +19,8 @@ impl ops::Deref for Folders {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<pimalaya_email::Folders> for Folders {
|
||||
fn from(folders: pimalaya_email::Folders) -> Self {
|
||||
impl From<pimalaya_email::folder::Folders> for Folders {
|
||||
fn from(folders: pimalaya_email::folder::Folders) -> Self {
|
||||
Folders(folders.iter().map(Folder::from).collect())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use anyhow::Result;
|
||||
use dialoguer::Confirm;
|
||||
use pimalaya_email::{AccountConfig, Backend};
|
||||
use pimalaya_email::{account::AccountConfig, backend::Backend};
|
||||
use std::process;
|
||||
|
||||
use crate::{
|
||||
|
@ -12,18 +12,22 @@ use crate::{
|
|||
Folders,
|
||||
};
|
||||
|
||||
pub fn expunge<P: Printer>(printer: &mut P, backend: &mut dyn Backend, folder: &str) -> Result<()> {
|
||||
backend.expunge_folder(folder)?;
|
||||
pub async fn expunge<P: Printer>(
|
||||
printer: &mut P,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
) -> Result<()> {
|
||||
backend.expunge_folder(folder).await?;
|
||||
printer.print(format!("Folder {folder} successfully expunged!"))
|
||||
}
|
||||
|
||||
pub fn list<P: Printer>(
|
||||
pub async fn list<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut dyn Backend,
|
||||
max_width: Option<usize>,
|
||||
) -> Result<()> {
|
||||
let folders: Folders = backend.list_folders()?.into();
|
||||
let folders: Folders = backend.list_folders().await?.into();
|
||||
printer.print_table(
|
||||
// TODO: remove Box
|
||||
Box::new(folders),
|
||||
|
@ -34,12 +38,20 @@ pub fn list<P: Printer>(
|
|||
)
|
||||
}
|
||||
|
||||
pub fn create<P: Printer>(printer: &mut P, backend: &mut dyn Backend, folder: &str) -> Result<()> {
|
||||
backend.add_folder(folder)?;
|
||||
pub async fn create<P: Printer>(
|
||||
printer: &mut P,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
) -> Result<()> {
|
||||
backend.add_folder(folder).await?;
|
||||
printer.print("Folder successfully created!")
|
||||
}
|
||||
|
||||
pub fn delete<P: Printer>(printer: &mut P, backend: &mut dyn Backend, folder: &str) -> Result<()> {
|
||||
pub async fn delete<P: Printer>(
|
||||
printer: &mut P,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
) -> Result<()> {
|
||||
if let Some(false) | None = Confirm::new()
|
||||
.with_prompt(format!("Confirm deletion of folder {folder}?"))
|
||||
.default(false)
|
||||
|
@ -49,14 +61,18 @@ pub fn delete<P: Printer>(printer: &mut P, backend: &mut dyn Backend, folder: &s
|
|||
process::exit(0);
|
||||
};
|
||||
|
||||
backend.delete_folder(folder)?;
|
||||
backend.delete_folder(folder).await?;
|
||||
printer.print("Folder successfully deleted!")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use async_trait::async_trait;
|
||||
use pimalaya_email::{
|
||||
backend, AccountConfig, Backend, Emails, Envelope, Envelopes, Flags, Folder, Folders,
|
||||
account::AccountConfig,
|
||||
backend::Backend,
|
||||
email::{Envelope, Envelopes, Flags, Messages},
|
||||
folder::{Folder, Folders},
|
||||
};
|
||||
use std::{any::Any, fmt::Debug, io};
|
||||
use termcolor::ColorSpec;
|
||||
|
@ -65,8 +81,8 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_should_list_mboxes() {
|
||||
#[tokio::test]
|
||||
async fn it_should_list_mboxes() {
|
||||
#[derive(Debug, Default, Clone)]
|
||||
struct StringWriter {
|
||||
content: String,
|
||||
|
@ -131,82 +147,119 @@ mod tests {
|
|||
|
||||
struct TestBackend;
|
||||
|
||||
#[async_trait]
|
||||
impl Backend for TestBackend {
|
||||
fn name(&self) -> String {
|
||||
unimplemented!();
|
||||
}
|
||||
fn add_folder(&mut self, _: &str) -> backend::Result<()> {
|
||||
async fn add_folder(&mut self, _: &str) -> pimalaya_email::Result<()> {
|
||||
unimplemented!();
|
||||
}
|
||||
fn list_folders(&mut self) -> backend::Result<Folders> {
|
||||
async fn list_folders(&mut self) -> pimalaya_email::Result<Folders> {
|
||||
Ok(Folders::from_iter([
|
||||
Folder {
|
||||
delim: "/".into(),
|
||||
name: "INBOX".into(),
|
||||
desc: "desc".into(),
|
||||
},
|
||||
Folder {
|
||||
delim: "/".into(),
|
||||
name: "Sent".into(),
|
||||
desc: "desc".into(),
|
||||
},
|
||||
]))
|
||||
}
|
||||
fn expunge_folder(&mut self, _: &str) -> backend::Result<()> {
|
||||
async fn expunge_folder(&mut self, _: &str) -> pimalaya_email::Result<()> {
|
||||
unimplemented!();
|
||||
}
|
||||
fn purge_folder(&mut self, _: &str) -> backend::Result<()> {
|
||||
async fn purge_folder(&mut self, _: &str) -> pimalaya_email::Result<()> {
|
||||
unimplemented!();
|
||||
}
|
||||
fn delete_folder(&mut self, _: &str) -> backend::Result<()> {
|
||||
async fn delete_folder(&mut self, _: &str) -> pimalaya_email::Result<()> {
|
||||
unimplemented!();
|
||||
}
|
||||
fn get_envelope(&mut self, _: &str, _: &str) -> backend::Result<Envelope> {
|
||||
async fn get_envelope(&mut self, _: &str, _: &str) -> pimalaya_email::Result<Envelope> {
|
||||
unimplemented!();
|
||||
}
|
||||
fn list_envelopes(
|
||||
async fn list_envelopes(
|
||||
&mut self,
|
||||
_: &str,
|
||||
_: usize,
|
||||
_: usize,
|
||||
) -> backend::Result<Envelopes> {
|
||||
) -> pimalaya_email::Result<Envelopes> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn search_envelopes(
|
||||
async fn search_envelopes(
|
||||
&mut self,
|
||||
_: &str,
|
||||
_: &str,
|
||||
_: &str,
|
||||
_: usize,
|
||||
_: usize,
|
||||
) -> backend::Result<Envelopes> {
|
||||
) -> pimalaya_email::Result<Envelopes> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn add_email(&mut self, _: &str, _: &[u8], _: &Flags) -> backend::Result<String> {
|
||||
async fn add_email(
|
||||
&mut self,
|
||||
_: &str,
|
||||
_: &[u8],
|
||||
_: &Flags,
|
||||
) -> pimalaya_email::Result<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_emails(&mut self, _: &str, _: Vec<&str>) -> backend::Result<Emails> {
|
||||
async fn get_emails(
|
||||
&mut self,
|
||||
_: &str,
|
||||
_: Vec<&str>,
|
||||
) -> pimalaya_email::Result<Messages> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn preview_emails(&mut self, _: &str, _: Vec<&str>) -> backend::Result<Emails> {
|
||||
async fn preview_emails(
|
||||
&mut self,
|
||||
_: &str,
|
||||
_: Vec<&str>,
|
||||
) -> pimalaya_email::Result<Messages> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn copy_emails(&mut self, _: &str, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
||||
async fn copy_emails(
|
||||
&mut self,
|
||||
_: &str,
|
||||
_: &str,
|
||||
_: Vec<&str>,
|
||||
) -> pimalaya_email::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn move_emails(&mut self, _: &str, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
||||
async fn move_emails(
|
||||
&mut self,
|
||||
_: &str,
|
||||
_: &str,
|
||||
_: Vec<&str>,
|
||||
) -> pimalaya_email::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn delete_emails(&mut self, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
||||
async fn delete_emails(&mut self, _: &str, _: Vec<&str>) -> pimalaya_email::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn add_flags(&mut self, _: &str, _: Vec<&str>, _: &Flags) -> backend::Result<()> {
|
||||
async fn add_flags(
|
||||
&mut self,
|
||||
_: &str,
|
||||
_: Vec<&str>,
|
||||
_: &Flags,
|
||||
) -> pimalaya_email::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn set_flags(&mut self, _: &str, _: Vec<&str>, _: &Flags) -> backend::Result<()> {
|
||||
async fn set_flags(
|
||||
&mut self,
|
||||
_: &str,
|
||||
_: Vec<&str>,
|
||||
_: &Flags,
|
||||
) -> pimalaya_email::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn remove_flags(&mut self, _: &str, _: Vec<&str>, _: &Flags) -> backend::Result<()> {
|
||||
async fn remove_flags(
|
||||
&mut self,
|
||||
_: &str,
|
||||
_: Vec<&str>,
|
||||
_: &Flags,
|
||||
) -> pimalaya_email::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
|
@ -218,13 +271,15 @@ mod tests {
|
|||
let mut printer = PrinterServiceTest::default();
|
||||
let mut backend = TestBackend {};
|
||||
|
||||
assert!(list(&account_config, &mut printer, &mut backend, None).is_ok());
|
||||
assert!(list(&account_config, &mut printer, &mut backend, None)
|
||||
.await
|
||||
.is_ok());
|
||||
assert_eq!(
|
||||
concat![
|
||||
"\n",
|
||||
"DELIM │NAME │DESC \n",
|
||||
"/ │INBOX │desc \n",
|
||||
"/ │Sent │desc \n",
|
||||
"NAME │DESC \n",
|
||||
"INBOX │desc \n",
|
||||
"Sent │desc \n",
|
||||
"\n"
|
||||
],
|
||||
printer.writer.content
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use anyhow::Result;
|
||||
use dialoguer::Input;
|
||||
use pimalaya_email::{SenderConfig, SendmailConfig};
|
||||
use pimalaya_email::sender::{SenderConfig, SendmailConfig};
|
||||
|
||||
use crate::config::wizard::THEME;
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use anyhow::Result;
|
||||
use dialoguer::{Confirm, Input, Select};
|
||||
use pimalaya_email::{
|
||||
OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig, SenderConfig, SmtpAuthConfig,
|
||||
SmtpConfig,
|
||||
account::{OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig},
|
||||
sender::{SenderConfig, SmtpAuthConfig, SmtpConfig},
|
||||
};
|
||||
use pimalaya_oauth2::{AuthorizationCodeGrant, Client};
|
||||
use pimalaya_secret::Secret;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use anyhow::Result;
|
||||
use dialoguer::Select;
|
||||
use pimalaya_email::SenderConfig;
|
||||
use pimalaya_email::sender::SenderConfig;
|
||||
|
||||
use crate::config::wizard::THEME;
|
||||
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use atty::Stream;
|
||||
use pimalaya_email::{AccountConfig, Backend, Email, Flags, Sender, Tpl};
|
||||
use pimalaya_email::{
|
||||
account::AccountConfig,
|
||||
backend::Backend,
|
||||
email::{Flags, Message, Tpl},
|
||||
sender::Sender,
|
||||
};
|
||||
use std::io::{stdin, BufRead};
|
||||
|
||||
use crate::{printer::Printer, IdMapper};
|
||||
|
||||
pub fn forward<P: Printer>(
|
||||
pub async fn forward<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
|
@ -19,19 +24,21 @@ pub fn forward<P: Printer>(
|
|||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
|
||||
let tpl: String = backend
|
||||
.get_emails(folder, ids)?
|
||||
.get_emails(folder, ids)
|
||||
.await?
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("cannot find email {}", id))?
|
||||
.to_forward_tpl_builder(config)
|
||||
.some_headers(headers)
|
||||
.some_body(body)
|
||||
.build()?
|
||||
.with_some_headers(headers)
|
||||
.with_some_body(body)
|
||||
.build()
|
||||
.await?
|
||||
.into();
|
||||
|
||||
printer.print(tpl)
|
||||
}
|
||||
|
||||
pub fn reply<P: Printer>(
|
||||
pub async fn reply<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
|
@ -46,20 +53,22 @@ pub fn reply<P: Printer>(
|
|||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
|
||||
let tpl: String = backend
|
||||
.get_emails(folder, ids)?
|
||||
.get_emails(folder, ids)
|
||||
.await?
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("cannot find email {}", id))?
|
||||
.to_reply_tpl_builder(config)
|
||||
.some_headers(headers)
|
||||
.some_body(body)
|
||||
.reply_all(all)
|
||||
.build()?
|
||||
.with_some_headers(headers)
|
||||
.with_some_body(body)
|
||||
.with_reply_all(all)
|
||||
.build()
|
||||
.await?
|
||||
.into();
|
||||
|
||||
printer.print(tpl)
|
||||
}
|
||||
|
||||
pub fn save<P: Printer>(
|
||||
pub async fn save<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
id_mapper: &IdMapper,
|
||||
|
@ -79,16 +88,17 @@ pub fn save<P: Printer>(
|
|||
})
|
||||
.some_pgp_sign_cmd(config.email_writing_sign_cmd.clone())
|
||||
.some_pgp_encrypt_cmd(config.email_writing_encrypt_cmd.clone())
|
||||
.compile()?
|
||||
.compile()
|
||||
.await?
|
||||
.write_to_vec()?;
|
||||
|
||||
let id = backend.add_email(folder, &email, &Flags::default())?;
|
||||
let id = backend.add_email(folder, &email, &Flags::default()).await?;
|
||||
id_mapper.create_alias(id)?;
|
||||
|
||||
printer.print("Template successfully saved!")
|
||||
}
|
||||
|
||||
pub fn send<P: Printer>(
|
||||
pub async fn send<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut dyn Backend,
|
||||
|
@ -108,26 +118,31 @@ pub fn send<P: Printer>(
|
|||
})
|
||||
.some_pgp_sign_cmd(config.email_writing_sign_cmd.clone())
|
||||
.some_pgp_encrypt_cmd(config.email_writing_encrypt_cmd.clone())
|
||||
.compile()?
|
||||
.compile()
|
||||
.await?
|
||||
.write_to_vec()?;
|
||||
sender.send(&email)?;
|
||||
|
||||
sender.send(&email).await?;
|
||||
|
||||
if config.email_sending_save_copy {
|
||||
backend.add_email(folder, &email, &Flags::default())?;
|
||||
backend.add_email(folder, &email, &Flags::default()).await?;
|
||||
}
|
||||
|
||||
printer.print("Template successfully sent!")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write<P: Printer>(
|
||||
pub async fn write<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
headers: Option<Vec<(&str, &str)>>,
|
||||
body: Option<&str>,
|
||||
) -> Result<()> {
|
||||
let tpl: String = Email::new_tpl_builder(config)
|
||||
.some_headers(headers)
|
||||
.some_body(body)
|
||||
.build()?
|
||||
let tpl: String = Message::new_tpl_builder(config)
|
||||
.with_some_headers(headers)
|
||||
.with_some_body(body)
|
||||
.build()
|
||||
.await?
|
||||
.into();
|
||||
|
||||
printer.print(tpl)
|
||||
|
|
256
src/main.rs
256
src/main.rs
|
@ -1,9 +1,11 @@
|
|||
use anyhow::{anyhow, Context, Result};
|
||||
use clap::Command;
|
||||
#[cfg(feature = "imap-backend")]
|
||||
use pimalaya_email::ImapBackend;
|
||||
use pimalaya_email::backend::ImapBackend;
|
||||
use pimalaya_email::{
|
||||
BackendBuilder, BackendConfig, BackendSyncBuilder, SenderBuilder, DEFAULT_INBOX_FOLDER,
|
||||
account::{sync::AccountSyncBuilder, DEFAULT_INBOX_FOLDER},
|
||||
backend::{BackendBuilder, BackendConfig},
|
||||
sender::SenderBuilder,
|
||||
};
|
||||
use std::env;
|
||||
use url::Url;
|
||||
|
@ -54,17 +56,20 @@ async fn main() -> Result<()> {
|
|||
let url = Url::parse(&raw_args[1])?;
|
||||
let config = DeserializedConfig::from_opt_path(None)?;
|
||||
let account_config = config.to_account_config(None)?;
|
||||
let mut backend = BackendBuilder::new(account_config.clone()).build()?;
|
||||
let mut sender = SenderBuilder::new(account_config.clone()).build()?;
|
||||
let mut backend = BackendBuilder::new(account_config.clone()).build().await?;
|
||||
let mut sender = SenderBuilder::new(account_config.clone()).build().await?;
|
||||
let mut printer = StdoutPrinter::default();
|
||||
|
||||
return email::handlers::mailto(
|
||||
email::handlers::mailto(
|
||||
&account_config,
|
||||
backend.as_mut(),
|
||||
sender.as_mut(),
|
||||
&mut printer,
|
||||
&url,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let app = create_app();
|
||||
|
@ -107,13 +112,15 @@ async fn main() -> Result<()> {
|
|||
match imap::args::matches(&m)? {
|
||||
Some(imap::args::Cmd::Notify(keepalive)) => {
|
||||
let mut backend =
|
||||
ImapBackend::new(account_config.clone(), imap_config.clone(), None)?;
|
||||
return imap::handlers::notify(&mut backend, &folder, keepalive);
|
||||
ImapBackend::new(account_config.clone(), imap_config.clone(), None).await?;
|
||||
imap::handlers::notify(&mut backend, &folder, keepalive).await?;
|
||||
return Ok(());
|
||||
}
|
||||
Some(imap::args::Cmd::Watch(keepalive)) => {
|
||||
let mut backend =
|
||||
ImapBackend::new(account_config.clone(), imap_config.clone(), None)?;
|
||||
return imap::handlers::watch(&mut backend, &folder, keepalive);
|
||||
ImapBackend::new(account_config.clone(), imap_config.clone(), None).await?;
|
||||
imap::handlers::watch(&mut backend, &folder, keepalive).await?;
|
||||
return Ok(());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -121,17 +128,20 @@ async fn main() -> Result<()> {
|
|||
|
||||
match account::args::matches(&m)? {
|
||||
Some(account::args::Cmd::List(max_width)) => {
|
||||
return account::handlers::list(max_width, &account_config, &config, &mut printer);
|
||||
account::handlers::list(max_width, &account_config, &config, &mut printer)?;
|
||||
return Ok(());
|
||||
}
|
||||
Some(account::args::Cmd::Sync(strategy, dry_run)) => {
|
||||
let sync_builder = BackendSyncBuilder::new(account_config, backend_builder)?
|
||||
let sync_builder = AccountSyncBuilder::new(account_config, backend_builder)
|
||||
.await?
|
||||
.with_some_folders_strategy(strategy)
|
||||
.with_dry_run(dry_run);
|
||||
account::handlers::sync(&mut printer, sync_builder, dry_run)?;
|
||||
account::handlers::sync(&mut printer, sync_builder, dry_run).await?;
|
||||
return Ok(());
|
||||
}
|
||||
Some(account::args::Cmd::Configure(reset)) => {
|
||||
return account::handlers::configure(&account_config, reset);
|
||||
account::handlers::configure(&account_config, reset).await?;
|
||||
return Ok(());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -143,30 +153,30 @@ async fn main() -> Result<()> {
|
|||
.ok_or_else(|| anyhow!("the folder argument is missing"))
|
||||
.context("cannot create folder")?;
|
||||
let folder = account_config.folder_alias(folder)?;
|
||||
let mut backend = backend_builder.build()?;
|
||||
return folder::handlers::create(&mut printer, backend.as_mut(), &folder);
|
||||
let mut backend = backend_builder.build().await?;
|
||||
folder::handlers::create(&mut printer, backend.as_mut(), &folder).await?;
|
||||
return Ok(());
|
||||
}
|
||||
Some(folder::args::Cmd::List(max_width)) => {
|
||||
let mut backend = backend_builder.build()?;
|
||||
return folder::handlers::list(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
backend.as_mut(),
|
||||
max_width,
|
||||
);
|
||||
let mut backend = backend_builder.build().await?;
|
||||
folder::handlers::list(&account_config, &mut printer, backend.as_mut(), max_width)
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
Some(folder::args::Cmd::Expunge) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.build()?;
|
||||
return folder::handlers::expunge(&mut printer, backend.as_mut(), &folder);
|
||||
let mut backend = backend_builder.build().await?;
|
||||
folder::handlers::expunge(&mut printer, backend.as_mut(), &folder).await?;
|
||||
return Ok(());
|
||||
}
|
||||
Some(folder::args::Cmd::Delete) => {
|
||||
let folder = folder
|
||||
.ok_or_else(|| anyhow!("the folder argument is missing"))
|
||||
.context("cannot delete folder")?;
|
||||
let folder = account_config.folder_alias(folder)?;
|
||||
let mut backend = backend_builder.build()?;
|
||||
return folder::handlers::delete(&mut printer, backend.as_mut(), &folder);
|
||||
let mut backend = backend_builder.build().await?;
|
||||
folder::handlers::delete(&mut printer, backend.as_mut(), &folder).await?;
|
||||
return Ok(());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -175,23 +185,25 @@ async fn main() -> Result<()> {
|
|||
match email::args::matches(&m)? {
|
||||
Some(email::args::Cmd::Attachments(ids)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
return email::handlers::attachments(
|
||||
email::handlers::attachments(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
ids,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
Some(email::args::Cmd::Copy(ids, to_folder)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return email::handlers::copy(
|
||||
email::handlers::copy(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
|
@ -199,29 +211,35 @@ async fn main() -> Result<()> {
|
|||
&folder,
|
||||
to_folder,
|
||||
ids,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(email::args::Cmd::Delete(ids)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return email::handlers::delete(
|
||||
email::handlers::delete(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
ids,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(email::args::Cmd::Forward(id, headers, body)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut sender = sender_builder.build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let mut sender = sender_builder.build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return email::handlers::forward(
|
||||
email::handlers::forward(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
|
@ -231,14 +249,17 @@ async fn main() -> Result<()> {
|
|||
id,
|
||||
headers,
|
||||
body,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(email::args::Cmd::List(max_width, page_size, page)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return email::handlers::list(
|
||||
email::handlers::list(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
|
@ -247,14 +268,17 @@ async fn main() -> Result<()> {
|
|||
max_width,
|
||||
page_size,
|
||||
page,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(email::args::Cmd::Move(ids, to_folder)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return email::handlers::move_(
|
||||
email::handlers::move_(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
|
@ -262,14 +286,17 @@ async fn main() -> Result<()> {
|
|||
&folder,
|
||||
to_folder,
|
||||
ids,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(email::args::Cmd::Read(ids, text_mime, raw, headers)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return email::handlers::read(
|
||||
email::handlers::read(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
|
@ -279,15 +306,18 @@ async fn main() -> Result<()> {
|
|||
text_mime,
|
||||
raw,
|
||||
headers,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(email::args::Cmd::Reply(id, all, headers, body)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut sender = sender_builder.build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let mut sender = sender_builder.build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return email::handlers::reply(
|
||||
email::handlers::reply(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
|
@ -298,28 +328,34 @@ async fn main() -> Result<()> {
|
|||
all,
|
||||
headers,
|
||||
body,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(email::args::Cmd::Save(raw_email)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return email::handlers::save(
|
||||
email::handlers::save(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
raw_email,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(email::args::Cmd::Search(query, max_width, page_size, page)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return email::handlers::search(
|
||||
email::handlers::search(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
|
@ -329,14 +365,17 @@ async fn main() -> Result<()> {
|
|||
max_width,
|
||||
page_size,
|
||||
page,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
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 mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return email::handlers::sort(
|
||||
email::handlers::sort(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
|
@ -347,71 +386,86 @@ async fn main() -> Result<()> {
|
|||
max_width,
|
||||
page_size,
|
||||
page,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(email::args::Cmd::Send(raw_email)) => {
|
||||
let mut backend = backend_builder.build()?;
|
||||
let mut sender = sender_builder.build()?;
|
||||
return email::handlers::send(
|
||||
let mut backend = backend_builder.build().await?;
|
||||
let mut sender = sender_builder.build().await?;
|
||||
email::handlers::send(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
backend.as_mut(),
|
||||
sender.as_mut(),
|
||||
raw_email,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(email::args::Cmd::Flag(m)) => match m {
|
||||
Some(flag::args::Cmd::Set(ids, ref flags)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return flag::handlers::set(
|
||||
flag::handlers::set(
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
ids,
|
||||
flags,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(flag::args::Cmd::Add(ids, ref flags)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return flag::handlers::add(
|
||||
flag::handlers::add(
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
ids,
|
||||
flags,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(flag::args::Cmd::Remove(ids, ref flags)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return flag::handlers::remove(
|
||||
flag::handlers::remove(
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
ids,
|
||||
flags,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
Some(email::args::Cmd::Tpl(m)) => match m {
|
||||
Some(tpl::args::Cmd::Forward(id, headers, body)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return tpl::handlers::forward(
|
||||
tpl::handlers::forward(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
|
@ -420,17 +474,21 @@ async fn main() -> Result<()> {
|
|||
id,
|
||||
headers,
|
||||
body,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(tpl::args::Cmd::Write(headers, body)) => {
|
||||
return tpl::handlers::write(&account_config, &mut printer, headers, body);
|
||||
tpl::handlers::write(&account_config, &mut printer, headers, body).await?;
|
||||
return Ok(());
|
||||
}
|
||||
Some(tpl::args::Cmd::Reply(id, all, headers, body)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return tpl::handlers::reply(
|
||||
tpl::handlers::reply(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
|
@ -440,48 +498,60 @@ async fn main() -> Result<()> {
|
|||
all,
|
||||
headers,
|
||||
body,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(tpl::args::Cmd::Save(tpl)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_name, &folder)?;
|
||||
|
||||
return tpl::handlers::save(
|
||||
tpl::handlers::save(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
tpl,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Some(tpl::args::Cmd::Send(tpl)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = backend_builder.clone().into_build()?;
|
||||
let mut sender = sender_builder.build()?;
|
||||
return tpl::handlers::send(
|
||||
let mut backend = backend_builder.clone().into_build().await?;
|
||||
let mut sender = sender_builder.build().await?;
|
||||
tpl::handlers::send(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
backend.as_mut(),
|
||||
sender.as_mut(),
|
||||
&folder,
|
||||
tpl,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
Some(email::args::Cmd::Write(headers, body)) => {
|
||||
let mut backend = backend_builder.build()?;
|
||||
let mut sender = sender_builder.build()?;
|
||||
return email::handlers::write(
|
||||
let mut backend = backend_builder.build().await?;
|
||||
let mut sender = sender_builder.build().await?;
|
||||
email::handlers::write(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
backend.as_mut(),
|
||||
sender.as_mut(),
|
||||
headers,
|
||||
body,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::{Context, Result};
|
||||
use pimalaya_email::Tpl;
|
||||
use pimalaya_email::email::Tpl;
|
||||
|
||||
use crate::printer::WriteColor;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::Result;
|
||||
use pimalaya_email::EmailTextPlainFormat;
|
||||
use pimalaya_email::email::EmailTextPlainFormat;
|
||||
use std::io;
|
||||
use termcolor::{self, StandardStream};
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use anyhow::{Context, Result};
|
||||
use log::debug;
|
||||
use pimalaya_email::{
|
||||
email::{local_draft_path, remove_local_draft},
|
||||
AccountConfig, Backend, Flag, Flags, Sender, Tpl,
|
||||
account::AccountConfig,
|
||||
backend::Backend,
|
||||
email::{local_draft_path, remove_local_draft, Flag, Flags, Tpl},
|
||||
sender::Sender,
|
||||
};
|
||||
use std::{env, fs, process::Command};
|
||||
|
||||
|
@ -37,7 +39,7 @@ pub fn open_with_local_draft() -> Result<Tpl> {
|
|||
open_with_tpl(Tpl::from(content))
|
||||
}
|
||||
|
||||
pub fn edit_tpl_with_editor<P: Printer>(
|
||||
pub async fn edit_tpl_with_editor<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut dyn Backend,
|
||||
|
@ -76,13 +78,16 @@ pub fn edit_tpl_with_editor<P: Printer>(
|
|||
let email = tpl
|
||||
.some_pgp_sign_cmd(config.email_writing_sign_cmd.clone())
|
||||
.some_pgp_encrypt_cmd(config.email_writing_encrypt_cmd.clone())
|
||||
.compile()?
|
||||
.compile()
|
||||
.await?
|
||||
.write_to_vec()?;
|
||||
sender.send(&email)?;
|
||||
sender.send(&email).await?;
|
||||
if config.email_sending_save_copy {
|
||||
let sent_folder = config.sent_folder_alias()?;
|
||||
printer.print_log(format!("Adding email to the {} folder…", sent_folder))?;
|
||||
backend.add_email(&sent_folder, &email, &Flags::from_iter([Flag::Seen]))?;
|
||||
backend
|
||||
.add_email(&sent_folder, &email, &Flags::from_iter([Flag::Seen]))
|
||||
.await?;
|
||||
}
|
||||
remove_local_draft()?;
|
||||
printer.print("Done!")?;
|
||||
|
@ -101,13 +106,16 @@ pub fn edit_tpl_with_editor<P: Printer>(
|
|||
let email = tpl
|
||||
.some_pgp_sign_cmd(config.email_writing_sign_cmd.clone())
|
||||
.some_pgp_encrypt_cmd(config.email_writing_encrypt_cmd.clone())
|
||||
.compile()?
|
||||
.compile()
|
||||
.await?
|
||||
.write_to_vec()?;
|
||||
backend.add_email(
|
||||
&draft_folder,
|
||||
&email,
|
||||
&Flags::from_iter([Flag::Seen, Flag::Draft]),
|
||||
)?;
|
||||
backend
|
||||
.add_email(
|
||||
&draft_folder,
|
||||
&email,
|
||||
&Flags::from_iter([Flag::Seen, Flag::Draft]),
|
||||
)
|
||||
.await?;
|
||||
remove_local_draft()?;
|
||||
printer.print(format!("Email successfully saved to {}", draft_folder))?;
|
||||
break;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use anyhow::{Context, Result};
|
||||
use log::trace;
|
||||
use pimalaya_email::EmailTextPlainFormat;
|
||||
use pimalaya_email::email::EmailTextPlainFormat;
|
||||
use termcolor::{Color, ColorSpec};
|
||||
use terminal_size::terminal_size;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
@ -267,6 +267,7 @@ where
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pimalaya_email::email::EmailTextPlainFormat;
|
||||
use std::io;
|
||||
|
||||
use super::*;
|
||||
|
|
Loading…
Reference in a new issue