mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-05 17:15:12 +00:00
clean process and account modules (#340)
This commit is contained in:
parent
a5c4fdaac6
commit
c0e002ea1b
|
@ -3,7 +3,7 @@
|
|||
//! This module gathers all account actions triggered by the CLI.
|
||||
|
||||
use anyhow::Result;
|
||||
use himalaya_lib::account::{AccountConfig, DeserializedConfig};
|
||||
use himalaya_lib::account::{Account, DeserializedConfig};
|
||||
use log::{info, trace};
|
||||
|
||||
use crate::{
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
|||
pub fn list<'a, P: PrinterService>(
|
||||
max_width: Option<usize>,
|
||||
config: &DeserializedConfig,
|
||||
account_config: &AccountConfig,
|
||||
account_config: &Account,
|
||||
printer: &mut P,
|
||||
) -> Result<()> {
|
||||
info!(">> account list handler");
|
||||
|
@ -38,7 +38,7 @@ pub fn list<'a, P: PrinterService>(
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use himalaya_lib::account::{
|
||||
AccountConfig, DeserializedAccountConfig, DeserializedConfig, DeserializedImapAccountConfig,
|
||||
Account, DeserializedAccountConfig, DeserializedConfig, DeserializedImapAccountConfig,
|
||||
};
|
||||
use std::{collections::HashMap, fmt::Debug, io, iter::FromIterator};
|
||||
use termcolor::ColorSpec;
|
||||
|
@ -122,7 +122,7 @@ mod tests {
|
|||
..DeserializedConfig::default()
|
||||
};
|
||||
|
||||
let account_config = AccountConfig::default();
|
||||
let account_config = Account::default();
|
||||
let mut printer = PrinterServiceTest::default();
|
||||
|
||||
assert!(list(None, &config, &account_config, &mut printer).is_ok());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use anyhow::{Context, Result};
|
||||
use himalaya_lib::{
|
||||
account::{AccountConfig, BackendConfig, DeserializedConfig, DEFAULT_INBOX_FOLDER},
|
||||
account::{Account, BackendConfig, DeserializedConfig, DEFAULT_INBOX_FOLDER},
|
||||
backend::Backend,
|
||||
};
|
||||
use std::{convert::TryFrom, env};
|
||||
|
@ -58,7 +58,7 @@ fn main() -> Result<()> {
|
|||
if raw_args.len() > 1 && raw_args[1].starts_with("mailto:") {
|
||||
let config = DeserializedConfig::from_opt_path(None)?;
|
||||
let (account_config, backend_config) =
|
||||
AccountConfig::from_config_and_opt_account_name(&config, None)?;
|
||||
Account::from_config_and_opt_account_name(&config, None)?;
|
||||
let mut printer = StdoutPrinter::from(OutputFmt::Plain);
|
||||
let url = Url::parse(&raw_args[1])?;
|
||||
let mut smtp = LettreService::from(&account_config);
|
||||
|
@ -114,7 +114,7 @@ fn main() -> Result<()> {
|
|||
// Init entities and services.
|
||||
let config = DeserializedConfig::from_opt_path(m.value_of("config"))?;
|
||||
let (account_config, backend_config) =
|
||||
AccountConfig::from_config_and_opt_account_name(&config, m.value_of("account"))?;
|
||||
Account::from_config_and_opt_account_name(&config, m.value_of("account"))?;
|
||||
let mbox = m
|
||||
.value_of("mbox-source")
|
||||
.or_else(|| account_config.mailboxes.get("inbox").map(|s| s.as_str()))
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//! This module gathers all mailbox actions triggered by the CLI.
|
||||
|
||||
use anyhow::Result;
|
||||
use himalaya_lib::{account::AccountConfig, backend::Backend};
|
||||
use himalaya_lib::{account::Account, backend::Backend};
|
||||
use log::{info, trace};
|
||||
|
||||
use crate::output::{PrintTableOpts, PrinterService};
|
||||
|
@ -11,7 +11,7 @@ use crate::output::{PrintTableOpts, PrinterService};
|
|||
/// Lists all mailboxes.
|
||||
pub fn list<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
||||
max_width: Option<usize>,
|
||||
config: &AccountConfig,
|
||||
config: &Account,
|
||||
printer: &mut P,
|
||||
backend: Box<&'a mut B>,
|
||||
) -> Result<()> {
|
||||
|
@ -170,7 +170,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
let config = AccountConfig::default();
|
||||
let config = Account::default();
|
||||
let mut printer = PrinterServiceTest::default();
|
||||
let mut backend = TestBackend {};
|
||||
let backend = Box::new(&mut backend);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
use anyhow::{Context, Result};
|
||||
use atty::Stream;
|
||||
use himalaya_lib::{
|
||||
account::{AccountConfig, DEFAULT_SENT_FOLDER},
|
||||
account::{Account, DEFAULT_SENT_FOLDER},
|
||||
backend::Backend,
|
||||
msg::{Msg, Part, Parts, TextPlainPart, TplOverride},
|
||||
};
|
||||
|
@ -28,7 +28,7 @@ use crate::{
|
|||
pub fn attachments<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
||||
seq: &str,
|
||||
mbox: &str,
|
||||
config: &AccountConfig,
|
||||
config: &Account,
|
||||
printer: &mut P,
|
||||
backend: Box<&'a mut B>,
|
||||
) -> Result<()> {
|
||||
|
@ -92,7 +92,7 @@ pub fn forward<'a, P: PrinterService, B: Backend<'a> + ?Sized, S: SmtpService>(
|
|||
attachments_paths: Vec<&str>,
|
||||
encrypt: bool,
|
||||
mbox: &str,
|
||||
config: &AccountConfig,
|
||||
config: &Account,
|
||||
printer: &mut P,
|
||||
backend: Box<&'a mut B>,
|
||||
smtp: &mut S,
|
||||
|
@ -112,7 +112,7 @@ pub fn list<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
|||
page_size: Option<usize>,
|
||||
page: usize,
|
||||
mbox: &str,
|
||||
config: &AccountConfig,
|
||||
config: &Account,
|
||||
printer: &mut P,
|
||||
imap: Box<&'a mut B>,
|
||||
) -> Result<()> {
|
||||
|
@ -134,7 +134,7 @@ pub fn list<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
|||
/// [mailto]: https://en.wikipedia.org/wiki/Mailto
|
||||
pub fn mailto<'a, P: PrinterService, B: Backend<'a> + ?Sized, S: SmtpService>(
|
||||
url: &Url,
|
||||
config: &AccountConfig,
|
||||
config: &Account,
|
||||
printer: &mut P,
|
||||
backend: Box<&'a mut B>,
|
||||
smtp: &mut S,
|
||||
|
@ -212,7 +212,7 @@ pub fn read<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
|||
raw: bool,
|
||||
headers: Vec<&str>,
|
||||
mbox: &str,
|
||||
config: &AccountConfig,
|
||||
config: &Account,
|
||||
printer: &mut P,
|
||||
backend: Box<&'a mut B>,
|
||||
) -> Result<()> {
|
||||
|
@ -233,7 +233,7 @@ pub fn reply<'a, P: PrinterService, B: Backend<'a> + ?Sized, S: SmtpService>(
|
|||
attachments_paths: Vec<&str>,
|
||||
encrypt: bool,
|
||||
mbox: &str,
|
||||
config: &AccountConfig,
|
||||
config: &Account,
|
||||
printer: &mut P,
|
||||
backend: Box<&'a mut B>,
|
||||
smtp: &mut S,
|
||||
|
@ -285,7 +285,7 @@ pub fn search<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
|||
page_size: Option<usize>,
|
||||
page: usize,
|
||||
mbox: &str,
|
||||
config: &AccountConfig,
|
||||
config: &Account,
|
||||
printer: &mut P,
|
||||
backend: Box<&'a mut B>,
|
||||
) -> Result<()> {
|
||||
|
@ -310,7 +310,7 @@ pub fn sort<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
|||
page_size: Option<usize>,
|
||||
page: usize,
|
||||
mbox: &str,
|
||||
config: &AccountConfig,
|
||||
config: &Account,
|
||||
printer: &mut P,
|
||||
backend: Box<&'a mut B>,
|
||||
) -> Result<()> {
|
||||
|
@ -330,7 +330,7 @@ pub fn sort<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
|||
/// Send a raw message.
|
||||
pub fn send<'a, P: PrinterService, B: Backend<'a> + ?Sized, S: SmtpService>(
|
||||
raw_msg: &str,
|
||||
config: &AccountConfig,
|
||||
config: &Account,
|
||||
printer: &mut P,
|
||||
backend: Box<&mut B>,
|
||||
smtp: &mut S,
|
||||
|
@ -371,7 +371,7 @@ pub fn write<'a, P: PrinterService, B: Backend<'a> + ?Sized, S: SmtpService>(
|
|||
tpl: TplOverride,
|
||||
attachments_paths: Vec<&str>,
|
||||
encrypt: bool,
|
||||
config: &AccountConfig,
|
||||
config: &Account,
|
||||
printer: &mut P,
|
||||
backend: Box<&'a mut B>,
|
||||
smtp: &mut S,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
use anyhow::Result;
|
||||
use atty::Stream;
|
||||
use himalaya_lib::{
|
||||
account::AccountConfig,
|
||||
account::Account,
|
||||
backend::Backend,
|
||||
msg::{Msg, TplOverride},
|
||||
};
|
||||
|
@ -16,7 +16,7 @@ use crate::{output::PrinterService, smtp::SmtpService};
|
|||
/// Generate a new message template.
|
||||
pub fn new<'a, P: PrinterService>(
|
||||
opts: TplOverride<'a>,
|
||||
account: &'a AccountConfig,
|
||||
account: &'a Account,
|
||||
printer: &'a mut P,
|
||||
) -> Result<()> {
|
||||
let tpl = Msg::default().to_tpl(opts, account)?;
|
||||
|
@ -29,7 +29,7 @@ pub fn reply<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
|||
all: bool,
|
||||
opts: TplOverride<'a>,
|
||||
mbox: &str,
|
||||
config: &'a AccountConfig,
|
||||
config: &'a Account,
|
||||
printer: &'a mut P,
|
||||
backend: Box<&'a mut B>,
|
||||
) -> Result<()> {
|
||||
|
@ -45,7 +45,7 @@ pub fn forward<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
|||
seq: &str,
|
||||
opts: TplOverride<'a>,
|
||||
mbox: &str,
|
||||
config: &'a AccountConfig,
|
||||
config: &'a Account,
|
||||
printer: &'a mut P,
|
||||
backend: Box<&'a mut B>,
|
||||
) -> Result<()> {
|
||||
|
@ -59,7 +59,7 @@ pub fn forward<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
|||
/// Saves a message based on a template.
|
||||
pub fn save<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
||||
mbox: &str,
|
||||
config: &AccountConfig,
|
||||
config: &Account,
|
||||
attachments_paths: Vec<&str>,
|
||||
tpl: &str,
|
||||
printer: &mut P,
|
||||
|
@ -84,7 +84,7 @@ pub fn save<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
|||
/// Sends a message based on a template.
|
||||
pub fn send<'a, P: PrinterService, B: Backend<'a> + ?Sized, S: SmtpService>(
|
||||
mbox: &str,
|
||||
account: &AccountConfig,
|
||||
account: &Account,
|
||||
attachments_paths: Vec<&str>,
|
||||
tpl: &str,
|
||||
printer: &mut P,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::Result;
|
||||
use himalaya_lib::account::Format;
|
||||
use himalaya_lib::account::TextPlainFormat;
|
||||
use std::io;
|
||||
use termcolor::{self, StandardStream};
|
||||
|
||||
|
@ -12,6 +12,6 @@ pub trait PrintTable {
|
|||
}
|
||||
|
||||
pub struct PrintTableOpts<'a> {
|
||||
pub format: &'a Format,
|
||||
pub format: &'a TextPlainFormat,
|
||||
pub max_width: Option<usize>,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::{Context, Result};
|
||||
use himalaya_lib::{account::AccountConfig, msg::Msg};
|
||||
use himalaya_lib::{account::Account, msg::Msg};
|
||||
use lettre::{
|
||||
self,
|
||||
transport::smtp::{
|
||||
|
@ -13,11 +13,11 @@ use std::convert::TryInto;
|
|||
use crate::output::pipe_cmd;
|
||||
|
||||
pub trait SmtpService {
|
||||
fn send(&mut self, account: &AccountConfig, msg: &Msg) -> Result<Vec<u8>>;
|
||||
fn send(&mut self, account: &Account, msg: &Msg) -> Result<Vec<u8>>;
|
||||
}
|
||||
|
||||
pub struct LettreService<'a> {
|
||||
account: &'a AccountConfig,
|
||||
account: &'a Account,
|
||||
transport: Option<SmtpTransport>,
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ impl LettreService<'_> {
|
|||
}
|
||||
|
||||
impl SmtpService for LettreService<'_> {
|
||||
fn send(&mut self, account: &AccountConfig, msg: &Msg) -> Result<Vec<u8>> {
|
||||
fn send(&mut self, account: &Account, msg: &Msg) -> Result<Vec<u8>> {
|
||||
let mut raw_msg = msg.into_sendable_msg(account)?.formatted();
|
||||
|
||||
let envelope: lettre::address::Envelope =
|
||||
|
@ -76,8 +76,8 @@ impl SmtpService for LettreService<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a AccountConfig> for LettreService<'a> {
|
||||
fn from(account: &'a AccountConfig) -> Self {
|
||||
impl<'a> From<&'a Account> for LettreService<'a> {
|
||||
fn from(account: &'a Account) -> Self {
|
||||
Self {
|
||||
account,
|
||||
transport: None,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use anyhow::{Context, Result};
|
||||
use himalaya_lib::{
|
||||
account::{AccountConfig, DEFAULT_DRAFT_FOLDER, DEFAULT_SENT_FOLDER},
|
||||
account::{Account, DEFAULT_DRAFT_FOLDER, DEFAULT_SENT_FOLDER},
|
||||
backend::Backend,
|
||||
msg::{local_draft_path, remove_local_draft, Msg, TplOverride},
|
||||
};
|
||||
|
@ -39,7 +39,7 @@ pub fn open_with_draft() -> Result<String> {
|
|||
open_with_tpl(tpl)
|
||||
}
|
||||
|
||||
fn _edit_msg_with_editor(msg: &Msg, tpl: TplOverride, account: &AccountConfig) -> Result<Msg> {
|
||||
fn _edit_msg_with_editor(msg: &Msg, tpl: TplOverride, account: &Account) -> Result<Msg> {
|
||||
let tpl = msg.to_tpl(tpl, account)?;
|
||||
let tpl = open_with_tpl(tpl)?;
|
||||
Msg::from_tpl(&tpl).context("cannot parse message from template")
|
||||
|
@ -48,7 +48,7 @@ fn _edit_msg_with_editor(msg: &Msg, tpl: TplOverride, account: &AccountConfig) -
|
|||
pub fn edit_msg_with_editor<'a, P: PrinterService, B: Backend<'a> + ?Sized, S: SmtpService>(
|
||||
mut msg: Msg,
|
||||
tpl: TplOverride,
|
||||
account: &AccountConfig,
|
||||
account: &Account,
|
||||
printer: &mut P,
|
||||
backend: Box<&'a mut B>,
|
||||
smtp: &mut S,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! [builder design pattern]: https://refactoring.guru/design-patterns/builder
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use himalaya_lib::account::Format;
|
||||
use himalaya_lib::account::TextPlainFormat;
|
||||
use log::trace;
|
||||
use termcolor::{Color, ColorSpec};
|
||||
use terminal_size;
|
||||
|
@ -169,11 +169,11 @@ where
|
|||
|
||||
/// Writes the table to the writer.
|
||||
fn print(writer: &mut dyn WriteColor, items: &[Self], opts: PrintTableOpts) -> Result<()> {
|
||||
let is_format_flowed = matches!(opts.format, Format::Flowed);
|
||||
let is_format_flowed = matches!(opts.format, TextPlainFormat::Flowed);
|
||||
let max_width = match opts.format {
|
||||
Format::Fixed(width) => opts.max_width.unwrap_or(*width),
|
||||
Format::Flowed => 0,
|
||||
Format::Auto => opts
|
||||
TextPlainFormat::Fixed(width) => opts.max_width.unwrap_or(*width),
|
||||
TextPlainFormat::Flowed => 0,
|
||||
TextPlainFormat::Auto => opts
|
||||
.max_width
|
||||
.or_else(|| terminal_size::terminal_size().map(|(w, _)| w.0 as usize))
|
||||
.unwrap_or(DEFAULT_TERM_WIDTH),
|
||||
|
|
|
@ -1,52 +1,78 @@
|
|||
//! Account config module.
|
||||
//!
|
||||
//! This module contains the representation of the user account.
|
||||
|
||||
use lettre::transport::smtp::authentication::Credentials as SmtpCredentials;
|
||||
use log::{debug, info, trace};
|
||||
use mailparse::MailAddr;
|
||||
use serde::Deserialize;
|
||||
use shellexpand;
|
||||
use std::{collections::HashMap, env, ffi::OsStr, fs, path::PathBuf, result};
|
||||
use std::{collections::HashMap, env, ffi::OsStr, fs, path::PathBuf};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::process;
|
||||
use crate::process::{self, ProcessError};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("cannot run encrypt file command")]
|
||||
RunEncryptFileCmdError(#[source] process::Error),
|
||||
#[error("cannot find pgp encrypt file command from config")]
|
||||
FindPgpEncryptFileCmdError,
|
||||
#[error("cannot find pgp decrypt file command from config")]
|
||||
FindPgpDecryptFileCmdError,
|
||||
pub const DEFAULT_PAGE_SIZE: usize = 10;
|
||||
pub const DEFAULT_SIG_DELIM: &str = "-- \n";
|
||||
|
||||
pub const DEFAULT_INBOX_FOLDER: &str = "INBOX";
|
||||
pub const DEFAULT_SENT_FOLDER: &str = "Sent";
|
||||
pub const DEFAULT_DRAFT_FOLDER: &str = "Drafts";
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum AccountError {
|
||||
#[error("cannot encrypt file using pgp")]
|
||||
EncryptFileError(#[source] ProcessError),
|
||||
#[error("cannot find encrypt file command from config file")]
|
||||
EncryptFileMissingCmdError,
|
||||
|
||||
#[error("cannot decrypt file using pgp")]
|
||||
DecryptFileError(#[source] ProcessError),
|
||||
#[error("cannot find decrypt file command from config file")]
|
||||
DecryptFileMissingCmdError,
|
||||
|
||||
#[error("cannot get smtp password")]
|
||||
GetSmtpPasswdError(#[source] ProcessError),
|
||||
#[error("cannot get smtp password: password is empty")]
|
||||
GetSmtpPasswdEmptyError,
|
||||
|
||||
#[cfg(feature = "imap-backend")]
|
||||
#[error("cannot get imap password")]
|
||||
GetImapPasswdError(#[source] ProcessError),
|
||||
#[cfg(feature = "imap-backend")]
|
||||
#[error("cannot get imap password: password is empty")]
|
||||
GetImapPasswdEmptyError,
|
||||
|
||||
#[error("cannot find default account")]
|
||||
FindDefaultAccountError,
|
||||
#[error("cannot find account \"{0}\"")]
|
||||
#[error("cannot find account {0}")]
|
||||
FindAccountError(String),
|
||||
#[error("cannot shell expand")]
|
||||
ShellExpandError(#[from] shellexpand::LookupError<env::VarError>),
|
||||
#[error("cannot parse account address")]
|
||||
ParseAccountAddressError(#[from] mailparse::MailParseError),
|
||||
#[error("cannot find account address from \"{0}\"")]
|
||||
FindAccountAddressError(String),
|
||||
#[error("cannot parse download file name from \"{0}\"")]
|
||||
ParseDownloadFileNameError(PathBuf),
|
||||
#[error("cannot find password")]
|
||||
FindPasswordError,
|
||||
#[error("cannot get smtp password")]
|
||||
GetSmtpPasswdError(#[source] process::Error),
|
||||
#[error("cannot get imap password")]
|
||||
GetImapPasswdError(#[source] process::Error),
|
||||
#[error("cannot decrypt pgp file")]
|
||||
DecryptPgpFileError(#[source] process::Error),
|
||||
#[error("cannot run notify command")]
|
||||
RunNotifyCmdError(#[source] process::Error),
|
||||
}
|
||||
#[error("cannot parse account address {0}")]
|
||||
ParseAccountAddrError(#[source] mailparse::MailParseError, String),
|
||||
#[error("cannot find account address in {0}")]
|
||||
ParseAccountAddrNotFoundError(String),
|
||||
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
#[cfg(feature = "maildir-backend")]
|
||||
#[error("cannot expand maildir path")]
|
||||
ExpandMaildirPathError(#[source] shellexpand::LookupError<env::VarError>),
|
||||
#[cfg(feature = "notmuch-backend")]
|
||||
#[error("cannot expand notmuch path")]
|
||||
ExpandNotmuchDatabasePathError(#[source] shellexpand::LookupError<env::VarError>),
|
||||
#[error("cannot expand mailbox alias {1}")]
|
||||
ExpandMboxAliasError(#[source] shellexpand::LookupError<env::VarError>, String),
|
||||
|
||||
#[error("cannot parse download file name from {0}")]
|
||||
ParseDownloadFileNameError(PathBuf),
|
||||
|
||||
#[error("cannot start the notify mode")]
|
||||
StartNotifyModeError(#[source] ProcessError),
|
||||
}
|
||||
|
||||
/// Represents the user account.
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct AccountConfig {
|
||||
pub struct Account {
|
||||
/// Represents the name of the user account.
|
||||
pub name: String,
|
||||
/// Makes this account the default one.
|
||||
|
@ -69,7 +95,7 @@ pub struct AccountConfig {
|
|||
pub watch_cmds: Vec<String>,
|
||||
/// Represents the text/plain format as defined in the
|
||||
/// [RFC2646](https://www.ietf.org/rfc/rfc2646.txt)
|
||||
pub format: Format,
|
||||
pub format: TextPlainFormat,
|
||||
/// Overrides the default headers displayed at the top of
|
||||
/// the read message.
|
||||
pub read_headers: Vec<String>,
|
||||
|
@ -99,13 +125,13 @@ pub struct AccountConfig {
|
|||
pub pgp_decrypt_cmd: Option<String>,
|
||||
}
|
||||
|
||||
impl<'a> AccountConfig {
|
||||
impl<'a> Account {
|
||||
/// Tries to create an account from a config and an optional
|
||||
/// account name.
|
||||
pub fn from_config_and_opt_account_name(
|
||||
config: &'a DeserializedConfig,
|
||||
account_name: Option<&str>,
|
||||
) -> Result<(AccountConfig, BackendConfig)> {
|
||||
) -> Result<(Account, BackendConfig), AccountError> {
|
||||
info!("begin: parsing account and backend configs from config and account name");
|
||||
|
||||
debug!("account name: {:?}", account_name.unwrap_or("default"));
|
||||
|
@ -126,12 +152,12 @@ impl<'a> AccountConfig {
|
|||
}
|
||||
})
|
||||
.map(|(name, account)| (name.to_owned(), account))
|
||||
.ok_or_else(|| Error::FindDefaultAccountError),
|
||||
.ok_or_else(|| AccountError::FindDefaultAccountError),
|
||||
Some(name) => config
|
||||
.accounts
|
||||
.get(name)
|
||||
.map(|account| (name.to_owned(), account))
|
||||
.ok_or_else(|| Error::FindAccountError(name.to_owned())),
|
||||
.ok_or_else(|| AccountError::FindAccountError(name.to_owned())),
|
||||
}?;
|
||||
|
||||
let base_account = account.to_base();
|
||||
|
@ -175,7 +201,7 @@ impl<'a> AccountConfig {
|
|||
.or_else(|| sig.map(|sig| sig.to_owned()))
|
||||
.map(|sig| format!("{}{}", sig_delim, sig.trim_end()));
|
||||
|
||||
let account_config = AccountConfig {
|
||||
let account_config = Account {
|
||||
name,
|
||||
display_name: base_account
|
||||
.name
|
||||
|
@ -234,13 +260,17 @@ impl<'a> AccountConfig {
|
|||
#[cfg(feature = "maildir-backend")]
|
||||
DeserializedAccountConfig::Maildir(config) => {
|
||||
BackendConfig::Maildir(MaildirBackendConfig {
|
||||
maildir_dir: shellexpand::full(&config.maildir_dir)?.to_string().into(),
|
||||
maildir_dir: shellexpand::full(&config.maildir_dir)
|
||||
.map_err(AccountError::ExpandMaildirPathError)?
|
||||
.to_string()
|
||||
.into(),
|
||||
})
|
||||
}
|
||||
#[cfg(feature = "notmuch-backend")]
|
||||
DeserializedAccountConfig::Notmuch(config) => {
|
||||
BackendConfig::Notmuch(NotmuchBackendConfig {
|
||||
notmuch_database_dir: shellexpand::full(&config.notmuch_database_dir)?
|
||||
notmuch_database_dir: shellexpand::full(&config.notmuch_database_dir)
|
||||
.map_err(AccountError::ExpandNotmuchDatabasePathError)?
|
||||
.to_string()
|
||||
.into(),
|
||||
})
|
||||
|
@ -253,7 +283,7 @@ impl<'a> AccountConfig {
|
|||
}
|
||||
|
||||
/// Builds the full RFC822 compliant address of the user account.
|
||||
pub fn address(&self) -> Result<MailAddr> {
|
||||
pub fn address(&self) -> Result<MailAddr, AccountError> {
|
||||
let has_special_chars = "()<>[]:;@.,".contains(|c| self.display_name.contains(c));
|
||||
let addr = if self.display_name.is_empty() {
|
||||
self.email.clone()
|
||||
|
@ -264,19 +294,21 @@ impl<'a> AccountConfig {
|
|||
format!("{} <{}>", self.display_name, self.email)
|
||||
};
|
||||
|
||||
Ok(mailparse::addrparse(&addr)?
|
||||
Ok(mailparse::addrparse(&addr)
|
||||
.map_err(|err| AccountError::ParseAccountAddrError(err, addr.to_owned()))?
|
||||
.first()
|
||||
.ok_or_else(|| Error::FindAccountAddressError(addr.into()))?
|
||||
.ok_or_else(|| AccountError::ParseAccountAddrNotFoundError(addr.to_owned()))?
|
||||
.clone())
|
||||
}
|
||||
|
||||
/// Builds the user account SMTP credentials.
|
||||
pub fn smtp_creds(&self) -> Result<SmtpCredentials> {
|
||||
let passwd = process::run_cmd(&self.smtp_passwd_cmd).map_err(Error::GetSmtpPasswdError)?;
|
||||
pub fn smtp_creds(&self) -> Result<SmtpCredentials, AccountError> {
|
||||
let passwd =
|
||||
process::run(&self.smtp_passwd_cmd).map_err(AccountError::GetSmtpPasswdError)?;
|
||||
let passwd = passwd
|
||||
.lines()
|
||||
.next()
|
||||
.ok_or_else(|| Error::FindPasswordError)?;
|
||||
.ok_or_else(|| AccountError::GetSmtpPasswdEmptyError)?;
|
||||
|
||||
Ok(SmtpCredentials::new(
|
||||
self.smtp_login.to_owned(),
|
||||
|
@ -285,27 +317,30 @@ impl<'a> AccountConfig {
|
|||
}
|
||||
|
||||
/// Encrypts a file.
|
||||
pub fn pgp_encrypt_file(&self, addr: &str, path: PathBuf) -> Result<String> {
|
||||
pub fn pgp_encrypt_file(&self, addr: &str, path: PathBuf) -> Result<String, AccountError> {
|
||||
if let Some(cmd) = self.pgp_encrypt_cmd.as_ref() {
|
||||
let encrypt_file_cmd = format!("{} {} {:?}", cmd, addr, path);
|
||||
Ok(process::run_cmd(&encrypt_file_cmd).map_err(Error::RunEncryptFileCmdError)?)
|
||||
Ok(process::run(&encrypt_file_cmd).map_err(AccountError::EncryptFileError)?)
|
||||
} else {
|
||||
Err(Error::FindPgpEncryptFileCmdError)
|
||||
Err(AccountError::EncryptFileMissingCmdError)
|
||||
}
|
||||
}
|
||||
|
||||
/// Decrypts a file.
|
||||
pub fn pgp_decrypt_file(&self, path: PathBuf) -> Result<String> {
|
||||
pub fn pgp_decrypt_file(&self, path: PathBuf) -> Result<String, AccountError> {
|
||||
if let Some(cmd) = self.pgp_decrypt_cmd.as_ref() {
|
||||
let decrypt_file_cmd = format!("{} {:?}", cmd, path);
|
||||
Ok(process::run_cmd(&decrypt_file_cmd).map_err(Error::DecryptPgpFileError)?)
|
||||
Ok(process::run(&decrypt_file_cmd).map_err(AccountError::DecryptFileError)?)
|
||||
} else {
|
||||
Err(Error::FindPgpDecryptFileCmdError)
|
||||
Err(AccountError::DecryptFileMissingCmdError)
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the download path from a file name.
|
||||
pub fn get_download_file_path<S: AsRef<str>>(&self, file_name: S) -> Result<PathBuf> {
|
||||
pub fn get_download_file_path<S: AsRef<str>>(
|
||||
&self,
|
||||
file_name: S,
|
||||
) -> Result<PathBuf, AccountError> {
|
||||
let file_path = self.downloads_dir.join(file_name.as_ref());
|
||||
self.get_unique_download_file_path(&file_path, |path, _count| path.is_file())
|
||||
}
|
||||
|
@ -316,7 +351,7 @@ impl<'a> AccountConfig {
|
|||
&self,
|
||||
original_file_path: &PathBuf,
|
||||
is_file: impl Fn(&PathBuf, u8) -> bool,
|
||||
) -> Result<PathBuf> {
|
||||
) -> Result<PathBuf, AccountError> {
|
||||
let mut count = 0;
|
||||
let file_ext = original_file_path
|
||||
.extension()
|
||||
|
@ -332,7 +367,9 @@ impl<'a> AccountConfig {
|
|||
.file_stem()
|
||||
.and_then(OsStr::to_str)
|
||||
.map(|fstem| format!("{}_{}{}", fstem, count, file_ext))
|
||||
.ok_or_else(|| Error::ParseDownloadFileNameError(file_path.to_owned()))?,
|
||||
.ok_or_else(|| {
|
||||
AccountError::ParseDownloadFileNameError(file_path.to_owned())
|
||||
})?,
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -340,7 +377,7 @@ impl<'a> AccountConfig {
|
|||
}
|
||||
|
||||
/// Runs the notify command.
|
||||
pub fn run_notify_cmd<S: AsRef<str>>(&self, subject: S, sender: S) -> Result<()> {
|
||||
pub fn run_notify_cmd<S: AsRef<str>>(&self, subject: S, sender: S) -> Result<(), AccountError> {
|
||||
let subject = subject.as_ref();
|
||||
let sender = sender.as_ref();
|
||||
|
||||
|
@ -351,19 +388,21 @@ impl<'a> AccountConfig {
|
|||
.map(|cmd| format!(r#"{} {:?} {:?}"#, cmd, subject, sender))
|
||||
.unwrap_or(default_cmd);
|
||||
|
||||
process::run_cmd(&cmd).map_err(Error::RunNotifyCmdError)?;
|
||||
process::run(&cmd).map_err(AccountError::StartNotifyModeError)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets the mailbox alias if exists, otherwise returns the
|
||||
/// mailbox. Also tries to expand shell variables.
|
||||
pub fn get_mbox_alias(&self, mbox: &str) -> Result<String> {
|
||||
pub fn get_mbox_alias(&self, mbox: &str) -> Result<String, AccountError> {
|
||||
let mbox = self
|
||||
.mailboxes
|
||||
.get(&mbox.trim().to_lowercase())
|
||||
.map(|s| s.as_str())
|
||||
.unwrap_or(mbox);
|
||||
let mbox = shellexpand::full(mbox).map(String::from)?;
|
||||
let mbox = shellexpand::full(mbox)
|
||||
.map(String::from)
|
||||
.map_err(|err| AccountError::ExpandMboxAliasError(err, mbox.to_owned()))?;
|
||||
Ok(mbox)
|
||||
}
|
||||
}
|
||||
|
@ -400,12 +439,13 @@ pub struct ImapBackendConfig {
|
|||
#[cfg(feature = "imap-backend")]
|
||||
impl ImapBackendConfig {
|
||||
/// Gets the IMAP password of the user account.
|
||||
pub fn imap_passwd(&self) -> Result<String> {
|
||||
let passwd = process::run_cmd(&self.imap_passwd_cmd).map_err(Error::GetImapPasswdError)?;
|
||||
pub fn imap_passwd(&self) -> Result<String, AccountError> {
|
||||
let passwd =
|
||||
process::run(&self.imap_passwd_cmd).map_err(AccountError::GetImapPasswdError)?;
|
||||
let passwd = passwd
|
||||
.lines()
|
||||
.next()
|
||||
.ok_or_else(|| Error::FindPasswordError)?;
|
||||
.ok_or_else(|| AccountError::GetImapPasswdEmptyError)?;
|
||||
Ok(passwd.to_string())
|
||||
}
|
||||
}
|
||||
|
@ -426,13 +466,39 @@ pub struct NotmuchBackendConfig {
|
|||
pub notmuch_database_dir: PathBuf,
|
||||
}
|
||||
|
||||
/// Represents the text/plain format as defined in the [RFC2646].
|
||||
///
|
||||
/// [RFC2646]: https://www.ietf.org/rfc/rfc2646.txt
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Deserialize)]
|
||||
#[serde(tag = "type", content = "width", rename_all = "lowercase")]
|
||||
pub enum TextPlainFormat {
|
||||
// Forces the content width with a fixed amount of pixels.
|
||||
Fixed(usize),
|
||||
// Makes the content fit the terminal.
|
||||
Auto,
|
||||
// Does not restrict the content.
|
||||
Flowed,
|
||||
}
|
||||
|
||||
impl Default for TextPlainFormat {
|
||||
fn default() -> Self {
|
||||
Self::Auto
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Hooks {
|
||||
pub pre_send: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_should_get_unique_download_file_path() {
|
||||
let account = AccountConfig::default();
|
||||
let account = Account::default();
|
||||
let path = PathBuf::from("downloads/file.ext");
|
||||
|
||||
// When file path is unique
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
//! Deserialized account config module.
|
||||
//!
|
||||
//! This module contains the raw deserialized representation of an
|
||||
//! account in the accounts section of the user configuration file.
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use crate::account::{Format, Hooks};
|
||||
use super::*;
|
||||
|
||||
pub trait ToDeserializedBaseAccountConfig {
|
||||
fn to_base(&self) -> DeserializedBaseAccountConfig;
|
||||
|
@ -53,9 +58,8 @@ macro_rules! make_account_config {
|
|||
pub notify_query: Option<String>,
|
||||
/// Overrides the watch commands for this account.
|
||||
pub watch_cmds: Option<Vec<String>>,
|
||||
/// Represents the text/plain format as defined in the
|
||||
/// [RFC2646](https://www.ietf.org/rfc/rfc2646.txt)
|
||||
pub format: Option<Format>,
|
||||
/// Represents the text/plain format.
|
||||
pub format: Option<TextPlainFormat>,
|
||||
/// Represents the default headers displayed at the top of
|
||||
/// the read message.
|
||||
#[serde(default)]
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
//! Deserialized config module.
|
||||
//!
|
||||
//! This module contains the raw deserialized representation of the
|
||||
//! user configuration file.
|
||||
|
||||
use log::{debug, trace};
|
||||
use serde::Deserialize;
|
||||
use std::{collections::HashMap, env, fs, io, path::PathBuf, result};
|
||||
use thiserror::Error;
|
||||
use toml;
|
||||
|
||||
use crate::account::DeserializedAccountConfig;
|
||||
|
||||
pub const DEFAULT_PAGE_SIZE: usize = 10;
|
||||
pub const DEFAULT_SIG_DELIM: &str = "-- \n";
|
||||
|
||||
pub const DEFAULT_INBOX_FOLDER: &str = "INBOX";
|
||||
pub const DEFAULT_SENT_FOLDER: &str = "Sent";
|
||||
pub const DEFAULT_DRAFT_FOLDER: &str = "Drafts";
|
||||
use super::*;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum DeserializeConfigError {
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
/// Represents the text/plain format as defined in the [RFC2646]. The
|
||||
/// format is then used by the table system to adjust the way it is
|
||||
/// rendered.
|
||||
///
|
||||
/// [RFC2646]: https://www.ietf.org/rfc/rfc2646.txt
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Deserialize)]
|
||||
#[serde(tag = "type", content = "width", rename_all = "lowercase")]
|
||||
pub enum Format {
|
||||
// Forces the content width with a fixed amount of pixels.
|
||||
Fixed(usize),
|
||||
// Makes the content fit the terminal.
|
||||
Auto,
|
||||
// Does not restrict the content.
|
||||
Flowed,
|
||||
}
|
||||
|
||||
impl Default for Format {
|
||||
fn default() -> Self {
|
||||
Self::Auto
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Hooks {
|
||||
pub pre_send: Option<String>,
|
||||
}
|
|
@ -1,16 +1,12 @@
|
|||
pub mod deserialized_config;
|
||||
pub use deserialized_config::*;
|
||||
//! Account module.
|
||||
//!
|
||||
//! This module contains everything related to the user configuration.
|
||||
|
||||
pub mod deserialized_account_config;
|
||||
pub use deserialized_account_config::*;
|
||||
|
||||
// pub mod account_handlers;
|
||||
|
||||
pub mod account_config;
|
||||
mod account_config;
|
||||
pub use account_config::*;
|
||||
|
||||
pub mod format;
|
||||
pub use format::*;
|
||||
mod deserialized_config;
|
||||
pub use deserialized_config::*;
|
||||
|
||||
pub mod hooks;
|
||||
pub use hooks::*;
|
||||
mod deserialized_account_config;
|
||||
pub use deserialized_account_config::*;
|
||||
|
|
|
@ -27,7 +27,7 @@ pub enum Error {
|
|||
ImapError(#[from] super::imap::Error),
|
||||
|
||||
#[error(transparent)]
|
||||
AccountError(#[from] account::Error),
|
||||
AccountError(#[from] account::AccountError),
|
||||
|
||||
#[error(transparent)]
|
||||
MsgError(#[from] msg::Error),
|
||||
|
|
|
@ -78,7 +78,7 @@ pub enum Error {
|
|||
LogoutError(#[source] imap::Error),
|
||||
|
||||
#[error(transparent)]
|
||||
AccountError(#[from] account::Error),
|
||||
AccountError(#[from] account::AccountError),
|
||||
#[error(transparent)]
|
||||
MsgError(#[from] msg::Error),
|
||||
}
|
||||
|
|
|
@ -8,26 +8,26 @@ use native_tls::{TlsConnector, TlsStream};
|
|||
use std::{collections::HashSet, convert::TryInto, net::TcpStream, thread};
|
||||
|
||||
use crate::{
|
||||
account::{AccountConfig, ImapBackendConfig},
|
||||
account::{Account, ImapBackendConfig},
|
||||
backend::{
|
||||
backend::Result, from_imap_fetch, from_imap_fetches,
|
||||
imap::msg_sort_criterion::SortCriteria, imap::Error, into_imap_flags, Backend,
|
||||
},
|
||||
mbox::{Mbox, Mboxes},
|
||||
msg::{Envelopes, Flags, Msg},
|
||||
process::run_cmd,
|
||||
process,
|
||||
};
|
||||
|
||||
type ImapSess = imap::Session<TlsStream<TcpStream>>;
|
||||
|
||||
pub struct ImapBackend<'a> {
|
||||
account_config: &'a AccountConfig,
|
||||
account_config: &'a Account,
|
||||
imap_config: &'a ImapBackendConfig,
|
||||
sess: Option<ImapSess>,
|
||||
}
|
||||
|
||||
impl<'a> ImapBackend<'a> {
|
||||
pub fn new(account_config: &'a AccountConfig, imap_config: &'a ImapBackendConfig) -> Self {
|
||||
pub fn new(account_config: &'a Account, imap_config: &'a ImapBackendConfig) -> Self {
|
||||
Self {
|
||||
account_config,
|
||||
imap_config,
|
||||
|
@ -187,7 +187,7 @@ impl<'a> ImapBackend<'a> {
|
|||
debug!("batch execution of {} cmd(s)", cmds.len());
|
||||
cmds.iter().for_each(|cmd| {
|
||||
debug!("running command {:?}…", cmd);
|
||||
let res = run_cmd(cmd);
|
||||
let res = process::run(cmd);
|
||||
debug!("{:?}", res);
|
||||
})
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@ use log::{debug, info, trace};
|
|||
use std::{env, ffi::OsStr, fs, path::PathBuf};
|
||||
|
||||
use crate::{
|
||||
account::{AccountConfig, MaildirBackendConfig},
|
||||
account::{Account, MaildirBackendConfig},
|
||||
backend::{backend::Result, maildir_envelopes, maildir_flags, Backend, IdMapper},
|
||||
mbox::{Mbox, Mboxes},
|
||||
msg::{Envelopes, Flags, Msg},
|
||||
|
@ -17,15 +17,12 @@ use super::MaildirError;
|
|||
|
||||
/// Represents the maildir backend.
|
||||
pub struct MaildirBackend<'a> {
|
||||
account_config: &'a AccountConfig,
|
||||
account_config: &'a Account,
|
||||
mdir: maildir::Maildir,
|
||||
}
|
||||
|
||||
impl<'a> MaildirBackend<'a> {
|
||||
pub fn new(
|
||||
account_config: &'a AccountConfig,
|
||||
maildir_config: &'a MaildirBackendConfig,
|
||||
) -> Self {
|
||||
pub fn new(account_config: &'a Account, maildir_config: &'a MaildirBackendConfig) -> Self {
|
||||
Self {
|
||||
account_config,
|
||||
mdir: maildir_config.maildir_dir.clone().into(),
|
||||
|
|
|
@ -2,7 +2,7 @@ use log::{debug, info, trace};
|
|||
use std::fs;
|
||||
|
||||
use crate::{
|
||||
account::{AccountConfig, NotmuchBackendConfig},
|
||||
account::{Account, NotmuchBackendConfig},
|
||||
backend::{
|
||||
backend::Result, notmuch_envelopes, Backend, IdMapper, MaildirBackend, NotmuchError,
|
||||
},
|
||||
|
@ -12,7 +12,7 @@ use crate::{
|
|||
|
||||
/// Represents the Notmuch backend.
|
||||
pub struct NotmuchBackend<'a> {
|
||||
account_config: &'a AccountConfig,
|
||||
account_config: &'a Account,
|
||||
notmuch_config: &'a NotmuchBackendConfig,
|
||||
pub mdir: &'a mut MaildirBackend<'a>,
|
||||
db: notmuch::Database,
|
||||
|
@ -20,7 +20,7 @@ pub struct NotmuchBackend<'a> {
|
|||
|
||||
impl<'a> NotmuchBackend<'a> {
|
||||
pub fn new(
|
||||
account_config: &'a AccountConfig,
|
||||
account_config: &'a Account,
|
||||
notmuch_config: &'a NotmuchBackendConfig,
|
||||
mdir: &'a mut MaildirBackend<'a>,
|
||||
) -> Result<NotmuchBackend<'a>> {
|
||||
|
|
|
@ -34,7 +34,7 @@ pub enum Error {
|
|||
ParseAddressError(#[from] lettre::address::AddressError),
|
||||
|
||||
#[error(transparent)]
|
||||
AccountError(#[from] account::Error),
|
||||
AccountError(#[from] account::AccountError),
|
||||
|
||||
#[error("cannot get content type of multipart")]
|
||||
GetMultipartContentTypeError,
|
||||
|
@ -47,7 +47,7 @@ pub enum Error {
|
|||
#[error("cannot write encrypted part to temporary file")]
|
||||
WriteEncryptedPartBodyError(#[source] io::Error),
|
||||
#[error("cannot write encrypted part to temporary file")]
|
||||
DecryptPartError(#[source] account::Error),
|
||||
DecryptPartError(#[source] account::AccountError),
|
||||
|
||||
#[error("cannot delete local draft: {1}")]
|
||||
DeleteLocalDraftError(#[source] io::Error, path::PathBuf),
|
||||
|
|
|
@ -17,7 +17,7 @@ use tree_magic;
|
|||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
account::{AccountConfig, DEFAULT_SIG_DELIM},
|
||||
account::{Account, DEFAULT_SIG_DELIM},
|
||||
msg::{
|
||||
from_addrs_to_sendable_addrs, from_addrs_to_sendable_mbox, from_slice_to_addrs, Addr,
|
||||
Addrs, BinaryPart, Error, Part, Parts, Result, TextPlainPart, TplOverride,
|
||||
|
@ -166,7 +166,7 @@ impl Msg {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn into_reply(mut self, all: bool, account: &AccountConfig) -> Result<Self> {
|
||||
pub fn into_reply(mut self, all: bool, account: &Account) -> Result<Self> {
|
||||
let account_addr = account.address()?;
|
||||
|
||||
// In-Reply-To
|
||||
|
@ -264,7 +264,7 @@ impl Msg {
|
|||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn into_forward(mut self, account: &AccountConfig) -> Result<Self> {
|
||||
pub fn into_forward(mut self, account: &Account) -> Result<Self> {
|
||||
let account_addr = account.address()?;
|
||||
|
||||
let prev_subject = self.subject.to_owned();
|
||||
|
@ -380,7 +380,7 @@ impl Msg {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_tpl(&self, opts: TplOverride, account: &AccountConfig) -> Result<String> {
|
||||
pub fn to_tpl(&self, opts: TplOverride, account: &Account) -> Result<String> {
|
||||
let account_addr: Addrs = vec![account.address()?].into();
|
||||
let mut tpl = String::default();
|
||||
|
||||
|
@ -463,10 +463,10 @@ impl Msg {
|
|||
let parsed_mail = mailparse::parse_mail(tpl.as_bytes()).map_err(Error::ParseTplError)?;
|
||||
|
||||
info!("end: building message from template");
|
||||
Self::from_parsed_mail(parsed_mail, &AccountConfig::default())
|
||||
Self::from_parsed_mail(parsed_mail, &Account::default())
|
||||
}
|
||||
|
||||
pub fn into_sendable_msg(&self, account: &AccountConfig) -> Result<lettre::Message> {
|
||||
pub fn into_sendable_msg(&self, account: &Account) -> Result<lettre::Message> {
|
||||
let mut msg_builder = lettre::Message::builder()
|
||||
.message_id(self.message_id.to_owned())
|
||||
.subject(self.subject.to_owned());
|
||||
|
@ -551,7 +551,7 @@ impl Msg {
|
|||
|
||||
pub fn from_parsed_mail(
|
||||
parsed_mail: mailparse::ParsedMail<'_>,
|
||||
config: &AccountConfig,
|
||||
config: &Account,
|
||||
) -> Result<Self> {
|
||||
trace!(">> build message from parsed mail");
|
||||
trace!("parsed mail: {:?}", parsed_mail);
|
||||
|
@ -623,7 +623,7 @@ impl Msg {
|
|||
&self,
|
||||
text_mime: &str,
|
||||
headers: Vec<&str>,
|
||||
config: &AccountConfig,
|
||||
config: &Account,
|
||||
) -> Result<String> {
|
||||
let mut all_headers = vec![];
|
||||
for h in config.read_headers.iter() {
|
||||
|
@ -750,10 +750,10 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_into_reply() {
|
||||
let config = AccountConfig {
|
||||
let config = Account {
|
||||
display_name: "Test".into(),
|
||||
email: "test-account@local".into(),
|
||||
..AccountConfig::default()
|
||||
..Account::default()
|
||||
};
|
||||
|
||||
// Checks that:
|
||||
|
@ -889,7 +889,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_to_readable() {
|
||||
let config = AccountConfig::default();
|
||||
let config = Account::default();
|
||||
let msg = Msg {
|
||||
parts: Parts(vec![Part::TextPlain(TextPlainPart {
|
||||
content: String::from("hello, world!"),
|
||||
|
@ -952,14 +952,14 @@ mod tests {
|
|||
.unwrap()
|
||||
);
|
||||
|
||||
let config = AccountConfig {
|
||||
let config = Account {
|
||||
read_headers: vec![
|
||||
"CusTOM-heaDER".into(),
|
||||
"Subject".into(),
|
||||
"from".into(),
|
||||
"cc".into(),
|
||||
],
|
||||
..AccountConfig::default()
|
||||
..Account::default()
|
||||
};
|
||||
// header present but empty in msg headers, empty config
|
||||
assert_eq!(
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
|||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{account::AccountConfig, msg};
|
||||
use crate::{account::Account, msg};
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize)]
|
||||
pub struct TextPlainPart {
|
||||
|
@ -50,7 +50,7 @@ impl Parts {
|
|||
}
|
||||
|
||||
pub fn from_parsed_mail<'a>(
|
||||
account: &'a AccountConfig,
|
||||
account: &'a Account,
|
||||
part: &'a mailparse::ParsedMail<'a>,
|
||||
) -> msg::Result<Self> {
|
||||
let mut parts = vec![];
|
||||
|
@ -80,7 +80,7 @@ impl DerefMut for Parts {
|
|||
}
|
||||
|
||||
fn build_parts_map_rec(
|
||||
account: &AccountConfig,
|
||||
account: &Account,
|
||||
parsed_mail: &mailparse::ParsedMail,
|
||||
parts: &mut Vec<Part>,
|
||||
) -> msg::Result<()> {
|
||||
|
@ -137,7 +137,7 @@ fn build_parts_map_rec(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn decrypt_part(account: &AccountConfig, msg: &mailparse::ParsedMail) -> msg::Result<String> {
|
||||
fn decrypt_part(account: &Account, msg: &mailparse::ParsedMail) -> msg::Result<String> {
|
||||
let msg_path = env::temp_dir().join(Uuid::new_v4().to_string());
|
||||
let msg_body = msg
|
||||
.get_body()
|
||||
|
|
|
@ -1,30 +1,34 @@
|
|||
//! Process module.
|
||||
//!
|
||||
//! This module contains cross platform helpers around the
|
||||
//! `std::process` crate.
|
||||
|
||||
use log::{debug, trace};
|
||||
use std::{io, process, result, string};
|
||||
use std::{io, process::Command, string};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("cannot run command: {1}")]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ProcessError {
|
||||
#[error("cannot run command {1:?}")]
|
||||
RunCmdError(#[source] io::Error, String),
|
||||
|
||||
#[error("cannot parse command output")]
|
||||
ParseCmdOutputError(#[source] string::FromUtf8Error),
|
||||
}
|
||||
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
pub fn run_cmd(cmd: &str) -> Result<String> {
|
||||
trace!(">> run command");
|
||||
pub fn run(cmd: &str) -> Result<String, ProcessError> {
|
||||
debug!(">> run command");
|
||||
debug!("command: {}", cmd);
|
||||
|
||||
let output = if cfg!(target_os = "windows") {
|
||||
process::Command::new("cmd").args(&["/C", cmd]).output()
|
||||
Command::new("cmd").args(&["/C", cmd]).output()
|
||||
} else {
|
||||
process::Command::new("sh").arg("-c").arg(cmd).output()
|
||||
Command::new("sh").arg("-c").arg(cmd).output()
|
||||
};
|
||||
let output = output.map_err(|err| Error::RunCmdError(err, cmd.to_string()))?;
|
||||
let output = String::from_utf8(output.stdout).map_err(Error::ParseCmdOutputError)?;
|
||||
let output = output.map_err(|err| ProcessError::RunCmdError(err, cmd.to_string()))?;
|
||||
let output = String::from_utf8(output.stdout).map_err(ProcessError::ParseCmdOutputError)?;
|
||||
|
||||
debug!("command output: {}", output);
|
||||
trace!("<< run command");
|
||||
trace!("command output: {}", output);
|
||||
debug!("<< run command");
|
||||
Ok(output)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#[cfg(feature = "imap-backend")]
|
||||
use himalaya_lib::{
|
||||
account::{AccountConfig, ImapBackendConfig},
|
||||
account::{Account, ImapBackendConfig},
|
||||
backend::{Backend, ImapBackend},
|
||||
};
|
||||
|
||||
|
@ -8,14 +8,14 @@ use himalaya_lib::{
|
|||
#[test]
|
||||
fn test_imap_backend() {
|
||||
// configure accounts
|
||||
let account_config = AccountConfig {
|
||||
let account_config = Account {
|
||||
smtp_host: "localhost".into(),
|
||||
smtp_port: 3465,
|
||||
smtp_starttls: false,
|
||||
smtp_insecure: true,
|
||||
smtp_login: "inbox@localhost".into(),
|
||||
smtp_passwd_cmd: "echo 'password'".into(),
|
||||
..AccountConfig::default()
|
||||
..Account::default()
|
||||
};
|
||||
let imap_config = ImapBackendConfig {
|
||||
imap_host: "localhost".into(),
|
||||
|
|
|
@ -2,7 +2,7 @@ use maildir::Maildir;
|
|||
use std::{collections::HashMap, env, fs, iter::FromIterator};
|
||||
|
||||
use himalaya_lib::{
|
||||
account::{AccountConfig, MaildirBackendConfig},
|
||||
account::{Account, MaildirBackendConfig},
|
||||
backend::{Backend, MaildirBackend},
|
||||
msg::Flag,
|
||||
};
|
||||
|
@ -19,9 +19,9 @@ fn test_maildir_backend() {
|
|||
mdir_sub.create_dirs().unwrap();
|
||||
|
||||
// configure accounts
|
||||
let account_config = AccountConfig {
|
||||
let account_config = Account {
|
||||
mailboxes: HashMap::from_iter([("subdir".into(), "Subdir".into())]),
|
||||
..AccountConfig::default()
|
||||
..Account::default()
|
||||
};
|
||||
let mdir_config = MaildirBackendConfig {
|
||||
maildir_dir: mdir.path().to_owned(),
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::{collections::HashMap, env, fs, iter::FromIterator};
|
|||
|
||||
#[cfg(feature = "notmuch-backend")]
|
||||
use himalaya_lib::{
|
||||
account::{AccountConfig, MaildirBackendConfig, NotmuchBackendConfig},
|
||||
account::{Account, MaildirBackendConfig, NotmuchBackendConfig},
|
||||
backend::{Backend, MaildirBackend, NotmuchBackend},
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue