mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-25 12:30:22 +00:00
take passwds from command instead of clear
This commit is contained in:
parent
84df58cf81
commit
34189ad8ad
6 changed files with 76 additions and 27 deletions
|
@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- List command with pagination [#19]
|
||||
- Icon in table when attachment is present [#16]
|
||||
- Multi-account [#17]
|
||||
- Password from command [#22]
|
||||
|
||||
[unreleased]: https://github.com/soywod/himalaya
|
||||
|
||||
|
@ -45,3 +46,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
[#17]: https://github.com/soywod/himalaya/issues/17
|
||||
[#19]: https://github.com/soywod/himalaya/issues/19
|
||||
[#21]: https://github.com/soywod/himalaya/issues/21
|
||||
[#22]: https://github.com/soywod/himalaya/issues/22
|
||||
|
|
|
@ -10,6 +10,8 @@ use std::{
|
|||
};
|
||||
use toml;
|
||||
|
||||
use crate::io::run_cmd;
|
||||
|
||||
// Error wrapper
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -21,11 +23,14 @@ pub enum Error {
|
|||
GetPathNotFoundError,
|
||||
GetAccountNotFoundError(String),
|
||||
GetAccountDefaultNotFoundError,
|
||||
ParseImapPasswdUtf8Error,
|
||||
ParseSmtpPasswdUtf8Error,
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "(config): ")?;
|
||||
write!(f, "config: ")?;
|
||||
|
||||
match self {
|
||||
Error::IoError(err) => err.fmt(f),
|
||||
Error::ParseTomlError(err) => err.fmt(f),
|
||||
|
@ -34,6 +39,8 @@ impl fmt::Display for Error {
|
|||
Error::GetPathNotFoundError => write!(f, "path not found"),
|
||||
Error::GetAccountNotFoundError(account) => write!(f, "account {} not found", account),
|
||||
Error::GetAccountDefaultNotFoundError => write!(f, "no default account found"),
|
||||
Error::ParseImapPasswdUtf8Error => write!(f, "imap passwd invalid utf8"),
|
||||
Error::ParseSmtpPasswdUtf8Error => write!(f, "smtp passwd invalid utf8"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,21 +82,35 @@ pub struct Account {
|
|||
pub imap_host: String,
|
||||
pub imap_port: u16,
|
||||
pub imap_login: String,
|
||||
pub imap_password: String,
|
||||
pub imap_passwd_cmd: String,
|
||||
|
||||
pub smtp_host: String,
|
||||
pub smtp_port: u16,
|
||||
pub smtp_login: String,
|
||||
pub smtp_password: String,
|
||||
pub smtp_passwd_cmd: String,
|
||||
}
|
||||
|
||||
impl Account {
|
||||
pub fn imap_addr(&self) -> (&str, u16) {
|
||||
(&self.imap_host, self.imap_port)
|
||||
pub fn imap_passwd(&self) -> Result<String> {
|
||||
let cmd = run_cmd(&self.imap_passwd_cmd)?;
|
||||
let passwd = String::from_utf8(cmd.stdout);
|
||||
let passwd = passwd.map_err(|_| Error::ParseImapPasswdUtf8Error)?;
|
||||
let passwd = passwd.trim_end_matches("\n").to_owned();
|
||||
|
||||
Ok(passwd)
|
||||
}
|
||||
|
||||
pub fn smtp_creds(&self) -> SmtpCredentials {
|
||||
SmtpCredentials::new(self.smtp_login.to_owned(), self.smtp_password.to_owned())
|
||||
pub fn smtp_creds(&self) -> Result<SmtpCredentials> {
|
||||
let cmd = run_cmd(&self.smtp_passwd_cmd)?;
|
||||
let passwd = String::from_utf8(cmd.stdout);
|
||||
let passwd = passwd.map_err(|_| Error::ParseImapPasswdUtf8Error)?;
|
||||
let passwd = passwd.trim_end_matches("\n").to_owned();
|
||||
|
||||
Ok(SmtpCredentials::new(self.smtp_login.to_owned(), passwd))
|
||||
}
|
||||
|
||||
pub fn imap_addr(&self) -> (&str, u16) {
|
||||
(&self.imap_host, self.imap_port)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
15
src/imap.rs
15
src/imap.rs
|
@ -2,7 +2,7 @@ use imap;
|
|||
use native_tls::{self, TlsConnector, TlsStream};
|
||||
use std::{fmt, net::TcpStream, result};
|
||||
|
||||
use crate::config::Account;
|
||||
use crate::config::{self, Account};
|
||||
use crate::mbox::Mbox;
|
||||
use crate::msg::Msg;
|
||||
|
||||
|
@ -16,15 +16,18 @@ pub enum Error {
|
|||
ReadEmailNotFoundError(String),
|
||||
ReadEmailEmptyPartError(String, String),
|
||||
ExtractAttachmentsEmptyError(String),
|
||||
ConfigError(config::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "(imap): ")?;
|
||||
write!(f, "imap: ")?;
|
||||
|
||||
match self {
|
||||
Error::CreateTlsConnectorError(err) => err.fmt(f),
|
||||
Error::CreateImapSession(err) => err.fmt(f),
|
||||
Error::ParseEmailError(err) => err.fmt(f),
|
||||
Error::ConfigError(err) => err.fmt(f),
|
||||
Error::ReadEmailNotFoundError(uid) => {
|
||||
write!(f, "no email found for uid {}", uid)
|
||||
}
|
||||
|
@ -56,6 +59,12 @@ impl From<mailparse::MailParseError> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<config::Error> for Error {
|
||||
fn from(err: config::Error) -> Error {
|
||||
Error::ConfigError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Result wrapper
|
||||
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
@ -73,7 +82,7 @@ impl<'a> ImapConnector<'a> {
|
|||
let tls = TlsConnector::new()?;
|
||||
let client = imap::connect(account.imap_addr(), &account.imap_host, &tls)?;
|
||||
let sess = client
|
||||
.login(&account.imap_login, &account.imap_password)
|
||||
.login(&account.imap_login, &account.imap_passwd()?)
|
||||
.map_err(|res| res.0)?;
|
||||
|
||||
Ok(Self { account, sess })
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::{
|
|||
fmt,
|
||||
fs::{remove_file, File},
|
||||
io::{self, Read, Write},
|
||||
process::Command,
|
||||
process::{Command, Output},
|
||||
result,
|
||||
};
|
||||
|
||||
|
@ -17,7 +17,8 @@ pub enum Error {
|
|||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "(input): ")?;
|
||||
write!(f, "input: ")?;
|
||||
|
||||
match self {
|
||||
Error::IoError(err) => err.fmt(f),
|
||||
Error::AskForSendingConfirmationError => write!(f, "action cancelled"),
|
||||
|
@ -68,3 +69,11 @@ pub fn ask_for_confirmation(prompt: &str) -> Result<()> {
|
|||
_ => Err(Error::AskForSendingConfirmationError),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_cmd(cmd: &str) -> io::Result<Output> {
|
||||
if cfg!(target_os = "windows") {
|
||||
Command::new("cmd").args(&["/C", cmd]).output()
|
||||
} else {
|
||||
Command::new("sh").arg("-c").arg(cmd).output()
|
||||
}
|
||||
}
|
26
src/main.rs
26
src/main.rs
|
@ -1,6 +1,6 @@
|
|||
mod config;
|
||||
mod imap;
|
||||
mod input;
|
||||
mod io;
|
||||
mod mbox;
|
||||
mod msg;
|
||||
mod smtp;
|
||||
|
@ -20,7 +20,7 @@ const DEFAULT_PAGE: usize = 0;
|
|||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
ConfigError(config::Error),
|
||||
InputError(input::Error),
|
||||
IoError(io::Error),
|
||||
MsgError(msg::Error),
|
||||
ImapError(imap::Error),
|
||||
SmtpError(smtp::Error),
|
||||
|
@ -30,7 +30,7 @@ impl fmt::Display for Error {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::ConfigError(err) => err.fmt(f),
|
||||
Error::InputError(err) => err.fmt(f),
|
||||
Error::IoError(err) => err.fmt(f),
|
||||
Error::MsgError(err) => err.fmt(f),
|
||||
Error::ImapError(err) => err.fmt(f),
|
||||
Error::SmtpError(err) => err.fmt(f),
|
||||
|
@ -44,9 +44,9 @@ impl From<config::Error> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<input::Error> for Error {
|
||||
fn from(err: input::Error) -> Error {
|
||||
Error::InputError(err)
|
||||
impl From<crate::io::Error> for Error {
|
||||
fn from(err: crate::io::Error) -> Error {
|
||||
Error::IoError(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,10 +329,10 @@ fn run() -> Result<()> {
|
|||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
|
||||
let tpl = Msg::build_new_tpl(&config, &account)?;
|
||||
let content = input::open_editor_with_tpl(&tpl.as_bytes())?;
|
||||
let content = io::open_editor_with_tpl(&tpl.as_bytes())?;
|
||||
let msg = Msg::from(content);
|
||||
|
||||
input::ask_for_confirmation("Send the message?")?;
|
||||
io::ask_for_confirmation("Send the message?")?;
|
||||
|
||||
println!("Sending …");
|
||||
smtp::send(&account, &msg.to_sendable_msg()?)?;
|
||||
|
@ -357,10 +357,10 @@ fn run() -> Result<()> {
|
|||
msg.build_reply_tpl(&config, &account)?
|
||||
};
|
||||
|
||||
let content = input::open_editor_with_tpl(&tpl.as_bytes())?;
|
||||
let content = io::open_editor_with_tpl(&tpl.as_bytes())?;
|
||||
let msg = Msg::from(content);
|
||||
|
||||
input::ask_for_confirmation("Send the message?")?;
|
||||
io::ask_for_confirmation("Send the message?")?;
|
||||
|
||||
println!("Sending …");
|
||||
smtp::send(&account, &msg.to_sendable_msg()?)?;
|
||||
|
@ -380,10 +380,10 @@ fn run() -> Result<()> {
|
|||
|
||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||
let tpl = msg.build_forward_tpl(&config, &account)?;
|
||||
let content = input::open_editor_with_tpl(&tpl.as_bytes())?;
|
||||
let content = io::open_editor_with_tpl(&tpl.as_bytes())?;
|
||||
let msg = Msg::from(content);
|
||||
|
||||
input::ask_for_confirmation("Send the message?")?;
|
||||
io::ask_for_confirmation("Send the message?")?;
|
||||
|
||||
println!("Sending …");
|
||||
smtp::send(&account, &msg.to_sendable_msg()?)?;
|
||||
|
@ -400,7 +400,7 @@ fn run() -> Result<()> {
|
|||
|
||||
fn main() {
|
||||
if let Err(err) = run() {
|
||||
eprintln!("Error {}", err);
|
||||
eprintln!("Error: {}", err);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
|
12
src/smtp.rs
12
src/smtp.rs
|
@ -1,13 +1,14 @@
|
|||
use lettre;
|
||||
use std::{fmt, result};
|
||||
|
||||
use crate::config::Account;
|
||||
use crate::config::{self, Account};
|
||||
|
||||
// Error wrapper
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
TransportError(lettre::transport::smtp::Error),
|
||||
ConfigError(config::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
|
@ -15,6 +16,7 @@ impl fmt::Display for Error {
|
|||
write!(f, "(smtp): ")?;
|
||||
match self {
|
||||
Error::TransportError(err) => err.fmt(f),
|
||||
Error::ConfigError(err) => err.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +27,12 @@ impl From<lettre::transport::smtp::Error> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<config::Error> for Error {
|
||||
fn from(err: config::Error) -> Error {
|
||||
Error::ConfigError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Result wrapper
|
||||
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
@ -35,7 +43,7 @@ pub fn send(account: &Account, msg: &lettre::Message) -> Result<()> {
|
|||
use lettre::Transport;
|
||||
|
||||
lettre::transport::smtp::SmtpTransport::relay(&account.smtp_host)?
|
||||
.credentials(account.smtp_creds())
|
||||
.credentials(account.smtp_creds()?)
|
||||
.build()
|
||||
.send(msg)
|
||||
.map(|_| Ok(()))?
|
||||
|
|
Loading…
Reference in a new issue