mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-19 22:51:13 +00:00
improve entities and services from and try_from
This commit is contained in:
parent
0ed1147f3d
commit
248240f52d
|
@ -1,6 +1,6 @@
|
||||||
use anyhow::{anyhow, Context, Error, Result};
|
use anyhow::{anyhow, Context, Error, Result};
|
||||||
use lettre::transport::smtp::authentication::Credentials as SmtpCredentials;
|
use lettre::transport::smtp::authentication::Credentials as SmtpCredentials;
|
||||||
use log::debug;
|
use log::{debug, trace};
|
||||||
use std::{convert::TryFrom, env, fs, path::PathBuf};
|
use std::{convert::TryFrom, env, fs, path::PathBuf};
|
||||||
|
|
||||||
use crate::{domain::config::entity::Config, output::utils::run_cmd};
|
use crate::{domain::config::entity::Config, output::utils::run_cmd};
|
||||||
|
@ -210,6 +210,7 @@ impl<'a> TryFrom<(&'a Config, Option<&str>)> for Account {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from((config, account_name): (&'a Config, Option<&str>)) -> Result<Self, Self::Error> {
|
fn try_from((config, account_name): (&'a Config, Option<&str>)) -> Result<Self, Self::Error> {
|
||||||
|
debug!("init account `{}`", account_name.unwrap_or("default"));
|
||||||
let (name, account) = match account_name {
|
let (name, account) = match account_name {
|
||||||
Some("") | None => config
|
Some("") | None => config
|
||||||
.accounts
|
.accounts
|
||||||
|
@ -265,7 +266,7 @@ impl<'a> TryFrom<(&'a Config, Option<&str>)> for Account {
|
||||||
.map(|sig| format!("\n{}{}", signature_delim, sig))
|
.map(|sig| format!("\n{}{}", signature_delim, sig))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
Ok(Account {
|
let account = Account {
|
||||||
name,
|
name,
|
||||||
from: account.name.as_ref().unwrap_or(&config.name).to_owned(),
|
from: account.name.as_ref().unwrap_or(&config.name).to_owned(),
|
||||||
downloads_dir,
|
downloads_dir,
|
||||||
|
@ -291,6 +292,9 @@ impl<'a> TryFrom<(&'a Config, Option<&str>)> for Account {
|
||||||
smtp_insecure: account.smtp_insecure.unwrap_or_default(),
|
smtp_insecure: account.smtp_insecure.unwrap_or_default(),
|
||||||
smtp_login: account.smtp_login.to_owned(),
|
smtp_login: account.smtp_login.to_owned(),
|
||||||
smtp_passwd_cmd: account.smtp_passwd_cmd.to_owned(),
|
smtp_passwd_cmd: account.smtp_passwd_cmd.to_owned(),
|
||||||
})
|
};
|
||||||
|
|
||||||
|
trace!("{:#?}", account);
|
||||||
|
Ok(account)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use anyhow::{anyhow, Context, Error, Result};
|
use anyhow::{anyhow, Context, Error, Result};
|
||||||
use log::debug;
|
use log::{debug, trace};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use shellexpand;
|
use shellexpand;
|
||||||
use std::{collections::HashMap, convert::TryFrom, env, fs, path::PathBuf, thread};
|
use std::{collections::HashMap, convert::TryFrom, env, fs, path::PathBuf, thread};
|
||||||
|
@ -284,12 +284,16 @@ impl Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<PathBuf> for Config {
|
impl TryFrom<Option<&str>> for Config {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from(path: PathBuf) -> Result<Self, Self::Error> {
|
fn try_from(path: Option<&str>) -> Result<Self, Self::Error> {
|
||||||
let file_content = fs::read_to_string(path).context("cannot read config file")?;
|
debug!("init config from `{:?}`", path);
|
||||||
Ok(toml::from_str(&file_content).context("cannot parse config file")?)
|
let path = path.map(|s| s.into()).unwrap_or(Config::path()?);
|
||||||
|
let content = fs::read_to_string(path).context("cannot read config file")?;
|
||||||
|
let config = toml::from_str(&content).context("cannot parse config file")?;
|
||||||
|
trace!("{:#?}", config);
|
||||||
|
Ok(config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,9 @@ use native_tls::{self, TlsConnector, TlsStream};
|
||||||
use std::{collections::HashSet, convert::TryFrom, iter::FromIterator, net::TcpStream};
|
use std::{collections::HashSet, convert::TryFrom, iter::FromIterator, net::TcpStream};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
domain::{account::entity::Account, config::entity::Config, msg::entity::Msg},
|
domain::{
|
||||||
|
account::entity::Account, config::entity::Config, mbox::entity::Mbox, msg::entity::Msg,
|
||||||
|
},
|
||||||
flag::model::Flags,
|
flag::model::Flags,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,7 +27,7 @@ pub trait ImapServiceInterface {
|
||||||
page: &usize,
|
page: &usize,
|
||||||
) -> Result<Option<ImapMsgs>>;
|
) -> Result<Option<ImapMsgs>>;
|
||||||
fn get_msg(&mut self, uid: &str) -> Result<Msg>;
|
fn get_msg(&mut self, uid: &str) -> Result<Msg>;
|
||||||
fn append_msg(&mut self, mbox: &str, msg: &mut Msg) -> Result<()>;
|
fn append_msg(&mut self, mbox: &Mbox, msg: &mut Msg) -> Result<()>;
|
||||||
fn add_flags(&mut self, uid_seq: &str, flags: Flags) -> Result<()>;
|
fn add_flags(&mut self, uid_seq: &str, flags: Flags) -> Result<()>;
|
||||||
fn set_flags(&mut self, uid_seq: &str, flags: Flags) -> Result<()>;
|
fn set_flags(&mut self, uid_seq: &str, flags: Flags) -> Result<()>;
|
||||||
fn remove_flags(&mut self, uid_seq: &str, flags: Flags) -> Result<()>;
|
fn remove_flags(&mut self, uid_seq: &str, flags: Flags) -> Result<()>;
|
||||||
|
@ -35,20 +37,11 @@ pub trait ImapServiceInterface {
|
||||||
|
|
||||||
pub struct ImapService<'a> {
|
pub struct ImapService<'a> {
|
||||||
account: &'a Account,
|
account: &'a Account,
|
||||||
mbox: &'a str,
|
mbox: &'a Mbox,
|
||||||
sess: Option<ImapSession>,
|
sess: Option<ImapSession>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ImapService<'a> {
|
impl<'a> ImapService<'a> {
|
||||||
pub fn new(account: &'a Account, mbox: &'a str) -> Result<Self> {
|
|
||||||
debug!("create new service");
|
|
||||||
Ok(Self {
|
|
||||||
account,
|
|
||||||
mbox,
|
|
||||||
sess: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sess(&mut self) -> Result<&mut ImapSession> {
|
fn sess(&mut self) -> Result<&mut ImapSession> {
|
||||||
if let None = self.sess {
|
if let None = self.sess {
|
||||||
debug!("create TLS builder");
|
debug!("create TLS builder");
|
||||||
|
@ -116,8 +109,8 @@ impl<'a> ImapServiceInterface for ImapService<'a> {
|
||||||
let mbox = self.mbox.to_owned();
|
let mbox = self.mbox.to_owned();
|
||||||
let last_seq = self
|
let last_seq = self
|
||||||
.sess()?
|
.sess()?
|
||||||
.select(mbox)
|
.select(&mbox.name)
|
||||||
.context(format!("cannot select mailbox `{}`", self.mbox))?
|
.context(format!("cannot select mailbox `{}`", self.mbox.name))?
|
||||||
.exists as i64;
|
.exists as i64;
|
||||||
|
|
||||||
if last_seq == 0 {
|
if last_seq == 0 {
|
||||||
|
@ -150,8 +143,8 @@ impl<'a> ImapServiceInterface for ImapService<'a> {
|
||||||
) -> Result<Option<ImapMsgs>> {
|
) -> Result<Option<ImapMsgs>> {
|
||||||
let mbox = self.mbox.to_owned();
|
let mbox = self.mbox.to_owned();
|
||||||
self.sess()?
|
self.sess()?
|
||||||
.select(mbox)
|
.select(&mbox.name)
|
||||||
.context(format!("cannot select mailbox `{}`", self.mbox))?;
|
.context(format!("cannot select mailbox `{}`", self.mbox.name))?;
|
||||||
|
|
||||||
let begin = page * page_size;
|
let begin = page * page_size;
|
||||||
let end = begin + (page_size - 1);
|
let end = begin + (page_size - 1);
|
||||||
|
@ -160,7 +153,7 @@ impl<'a> ImapServiceInterface for ImapService<'a> {
|
||||||
.search(query)
|
.search(query)
|
||||||
.context(format!(
|
.context(format!(
|
||||||
"cannot search in `{}` with query `{}`",
|
"cannot search in `{}` with query `{}`",
|
||||||
self.mbox, query
|
self.mbox.name, query
|
||||||
))?
|
))?
|
||||||
.iter()
|
.iter()
|
||||||
.map(|seq| seq.to_string())
|
.map(|seq| seq.to_string())
|
||||||
|
@ -182,8 +175,8 @@ impl<'a> ImapServiceInterface for ImapService<'a> {
|
||||||
fn get_msg(&mut self, uid: &str) -> Result<Msg> {
|
fn get_msg(&mut self, uid: &str) -> Result<Msg> {
|
||||||
let mbox = self.mbox.to_owned();
|
let mbox = self.mbox.to_owned();
|
||||||
self.sess()?
|
self.sess()?
|
||||||
.select(mbox)
|
.select(&mbox.name)
|
||||||
.context(format!("cannot select mbox `{}`", self.mbox))?;
|
.context(format!("cannot select mbox `{}`", self.mbox.name))?;
|
||||||
match self
|
match self
|
||||||
.sess()?
|
.sess()?
|
||||||
.uid_fetch(uid, "(FLAGS BODY[] ENVELOPE INTERNALDATE)")
|
.uid_fetch(uid, "(FLAGS BODY[] ENVELOPE INTERNALDATE)")
|
||||||
|
@ -195,14 +188,14 @@ impl<'a> ImapServiceInterface for ImapService<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_msg(&mut self, mbox: &str, msg: &mut Msg) -> Result<()> {
|
fn append_msg(&mut self, mbox: &Mbox, msg: &mut Msg) -> Result<()> {
|
||||||
let body = msg.into_bytes()?;
|
let body = msg.into_bytes()?;
|
||||||
let flags: HashSet<imap::types::Flag<'static>> = (*msg.flags).clone();
|
let flags: HashSet<imap::types::Flag<'static>> = (*msg.flags).clone();
|
||||||
self.sess()?
|
self.sess()?
|
||||||
.append(mbox, &body)
|
.append(&mbox.name, &body)
|
||||||
.flags(flags)
|
.flags(flags)
|
||||||
.finish()
|
.finish()
|
||||||
.context(format!("cannot append message to `{}`", mbox))?;
|
.context(format!("cannot append message to `{}`", mbox.name))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,8 +223,8 @@ impl<'a> ImapServiceInterface for ImapService<'a> {
|
||||||
let mbox = self.mbox.to_owned();
|
let mbox = self.mbox.to_owned();
|
||||||
let flags: String = flags.to_string();
|
let flags: String = flags.to_string();
|
||||||
self.sess()?
|
self.sess()?
|
||||||
.select(mbox)
|
.select(&mbox.name)
|
||||||
.context(format!("cannot select mbox `{}`", self.mbox))?;
|
.context(format!("cannot select mbox `{}`", self.mbox.name))?;
|
||||||
self.sess()?
|
self.sess()?
|
||||||
.uid_store(uid_seq, format!("+FLAGS ({})", flags))
|
.uid_store(uid_seq, format!("+FLAGS ({})", flags))
|
||||||
.context(format!("cannot add flags `{}`", &flags))?;
|
.context(format!("cannot add flags `{}`", &flags))?;
|
||||||
|
@ -263,8 +256,8 @@ impl<'a> ImapServiceInterface for ImapService<'a> {
|
||||||
let mbox = self.mbox.to_owned();
|
let mbox = self.mbox.to_owned();
|
||||||
let flags: String = flags.to_string();
|
let flags: String = flags.to_string();
|
||||||
self.sess()?
|
self.sess()?
|
||||||
.select(mbox)
|
.select(&mbox.name)
|
||||||
.context(format!("cannot select mailbox `{}`", self.mbox))?;
|
.context(format!("cannot select mailbox `{}`", self.mbox.name))?;
|
||||||
self.sess()?
|
self.sess()?
|
||||||
.uid_store(uid_seq, format!("FLAGS ({})", flags))
|
.uid_store(uid_seq, format!("FLAGS ({})", flags))
|
||||||
.context(format!("cannot set flags `{}`", &flags))?;
|
.context(format!("cannot set flags `{}`", &flags))?;
|
||||||
|
@ -277,8 +270,8 @@ impl<'a> ImapServiceInterface for ImapService<'a> {
|
||||||
let mbox = self.mbox.to_owned();
|
let mbox = self.mbox.to_owned();
|
||||||
let flags = flags.to_string();
|
let flags = flags.to_string();
|
||||||
self.sess()?
|
self.sess()?
|
||||||
.select(mbox)
|
.select(&mbox.name)
|
||||||
.context(format!("cannot select mailbox `{}`", self.mbox))?;
|
.context(format!("cannot select mailbox `{}`", self.mbox.name))?;
|
||||||
self.sess()?
|
self.sess()?
|
||||||
.uid_store(uid_seq, format!("-FLAGS ({})", flags))
|
.uid_store(uid_seq, format!("-FLAGS ({})", flags))
|
||||||
.context(format!("cannot remove flags `{}`", &flags))?;
|
.context(format!("cannot remove flags `{}`", &flags))?;
|
||||||
|
@ -288,17 +281,17 @@ impl<'a> ImapServiceInterface for ImapService<'a> {
|
||||||
fn expunge(&mut self) -> Result<()> {
|
fn expunge(&mut self) -> Result<()> {
|
||||||
self.sess()?
|
self.sess()?
|
||||||
.expunge()
|
.expunge()
|
||||||
.context(format!("cannot expunge `{}`", self.mbox))?;
|
.context(format!("cannot expunge `{}`", self.mbox.name))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notify(&mut self, config: &Config, keepalive: u64) -> Result<()> {
|
fn notify(&mut self, config: &Config, keepalive: u64) -> Result<()> {
|
||||||
let mbox = self.mbox.to_owned();
|
let mbox = self.mbox.to_owned();
|
||||||
|
|
||||||
debug!("examine mailbox: {}", mbox);
|
debug!("examine mailbox: {}", mbox.name);
|
||||||
self.sess()?
|
self.sess()?
|
||||||
.examine(mbox)
|
.examine(&mbox.name)
|
||||||
.context(format!("cannot examine mailbox `{}`", &self.mbox))?;
|
.context(format!("cannot examine mailbox `{}`", &self.mbox.name))?;
|
||||||
|
|
||||||
debug!("init messages hashset");
|
debug!("init messages hashset");
|
||||||
let mut msgs_set: HashSet<u32> =
|
let mut msgs_set: HashSet<u32> =
|
||||||
|
@ -361,12 +354,12 @@ impl<'a> ImapServiceInterface for ImapService<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn watch(&mut self, keepalive: u64) -> Result<()> {
|
fn watch(&mut self, keepalive: u64) -> Result<()> {
|
||||||
debug!("examine mailbox: {}", &self.mbox);
|
debug!("examine mailbox: {}", &self.mbox.name);
|
||||||
let mbox = self.mbox.to_owned();
|
let mbox = self.mbox.to_owned();
|
||||||
|
|
||||||
self.sess()?
|
self.sess()?
|
||||||
.examine(mbox)
|
.examine(&mbox.name)
|
||||||
.context(format!("cannot examine mailbox `{}`", &self.mbox))?;
|
.context(format!("cannot examine mailbox `{}`", &self.mbox.name))?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
debug!("begin loop");
|
debug!("begin loop");
|
||||||
|
@ -396,6 +389,12 @@ impl<'a> ImapServiceInterface for ImapService<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//impl<'a> ImapConnector<'a> {
|
impl<'a> From<(&'a Account, &'a Mbox)> for ImapService<'a> {
|
||||||
|
fn from((account, mbox): (&'a Account, &'a Mbox)) -> Self {
|
||||||
//}
|
Self {
|
||||||
|
account,
|
||||||
|
mbox,
|
||||||
|
sess: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
|
use anyhow::{anyhow, Error, Result};
|
||||||
use imap::types::NameAttribute;
|
use imap::types::NameAttribute;
|
||||||
|
use log::debug;
|
||||||
use serde::{
|
use serde::{
|
||||||
ser::{self, SerializeSeq},
|
ser::{self, SerializeSeq},
|
||||||
Serialize,
|
Serialize,
|
||||||
};
|
};
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::{borrow::Cow, convert::TryFrom};
|
||||||
|
|
||||||
use crate::ui::table::{Cell, Row, Table};
|
use crate::ui::table::{Cell, Row, Table};
|
||||||
|
|
||||||
|
@ -99,6 +101,41 @@ pub struct Mbox {
|
||||||
pub attributes: Attributes,
|
pub attributes: Attributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Mbox {
|
||||||
|
pub fn new<S: AsRef<str>>(name: S) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.as_ref().to_owned(),
|
||||||
|
..Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Mbox {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
delim: String::default(),
|
||||||
|
name: String::default(),
|
||||||
|
attributes: Attributes::from(&[] as &[NameAttribute]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Mbox {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Mbox {
|
||||||
|
fn from(mbox: &str) -> Self {
|
||||||
|
debug!("init mailbox from `{:?}`", mbox);
|
||||||
|
Self {
|
||||||
|
name: mbox.to_owned(),
|
||||||
|
..Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a imap::types::Name> for Mbox {
|
impl<'a> From<&'a imap::types::Name> for Mbox {
|
||||||
fn from(name: &'a imap::types::Name) -> Self {
|
fn from(name: &'a imap::types::Name) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -109,6 +146,18 @@ impl<'a> From<&'a imap::types::Name> for Mbox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Option<&str>> for Mbox {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from(mbox: Option<&str>) -> Result<Self, Self::Error> {
|
||||||
|
debug!("init mailbox from `{:?}`", mbox);
|
||||||
|
Ok(Self {
|
||||||
|
name: mbox.ok_or(anyhow!("cannot parse mailbox"))?.to_string(),
|
||||||
|
..Self::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Table for Mbox {
|
impl Table for Mbox {
|
||||||
fn head() -> Row {
|
fn head() -> Row {
|
||||||
Row::new()
|
Row::new()
|
||||||
|
|
|
@ -20,7 +20,9 @@ use super::{
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
domain::{
|
domain::{
|
||||||
account::entity::Account, imap::service::ImapServiceInterface, mbox::cli::mbox_target_arg,
|
account::entity::Account,
|
||||||
|
imap::service::ImapServiceInterface,
|
||||||
|
mbox::{cli::mbox_target_arg, entity::Mbox},
|
||||||
smtp::service::SmtpServiceInterface,
|
smtp::service::SmtpServiceInterface,
|
||||||
},
|
},
|
||||||
flag::model::Flags,
|
flag::model::Flags,
|
||||||
|
@ -130,7 +132,7 @@ pub fn subcmds<'a>() -> Vec<clap::App<'a, 'a>> {
|
||||||
|
|
||||||
pub fn matches<ImapService: ImapServiceInterface, SmtpService: SmtpServiceInterface>(
|
pub fn matches<ImapService: ImapServiceInterface, SmtpService: SmtpServiceInterface>(
|
||||||
arg_matches: &clap::ArgMatches,
|
arg_matches: &clap::ArgMatches,
|
||||||
mbox: &str,
|
mbox: &Mbox,
|
||||||
account: &Account,
|
account: &Account,
|
||||||
output: &OutputService,
|
output: &OutputService,
|
||||||
imap: &mut ImapService,
|
imap: &mut ImapService,
|
||||||
|
@ -578,14 +580,13 @@ fn msg_matches_copy<ImapService: ImapServiceInterface>(
|
||||||
// fetch the message to be copyied
|
// fetch the message to be copyied
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
debug!("uid: {}", &uid);
|
debug!("uid: {}", &uid);
|
||||||
let target = matches.value_of("target").unwrap();
|
let target = Mbox::try_from(matches.value_of("target"))?;
|
||||||
debug!("target: {}", &target);
|
|
||||||
|
|
||||||
let mut msg = imap.get_msg(&uid)?;
|
let mut msg = imap.get_msg(&uid)?;
|
||||||
// the message, which will be in the new mailbox doesn't need to be seen
|
// the message, which will be in the new mailbox doesn't need to be seen
|
||||||
msg.flags.insert(Flag::Seen);
|
msg.flags.insert(Flag::Seen);
|
||||||
|
|
||||||
imap.append_msg(target, &mut msg)?;
|
imap.append_msg(&target, &mut msg)?;
|
||||||
|
|
||||||
debug!("message {} successfully copied to folder `{}`", uid, target);
|
debug!("message {} successfully copied to folder `{}`", uid, target);
|
||||||
|
|
||||||
|
@ -608,13 +609,12 @@ fn msg_matches_move<ImapService: ImapServiceInterface>(
|
||||||
// fetch the msg which should be moved
|
// fetch the msg which should be moved
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
debug!("uid: {}", &uid);
|
debug!("uid: {}", &uid);
|
||||||
let target = matches.value_of("target").unwrap();
|
let target = Mbox::try_from(matches.value_of("target"))?;
|
||||||
debug!("target: {}", &target);
|
|
||||||
|
|
||||||
let mut msg = imap.get_msg(&uid)?;
|
let mut msg = imap.get_msg(&uid)?;
|
||||||
// create the msg in the target-msgbox
|
// create the msg in the target-msgbox
|
||||||
msg.flags.insert(Flag::Seen);
|
msg.flags.insert(Flag::Seen);
|
||||||
imap.append_msg(target, &mut msg)?;
|
imap.append_msg(&target, &mut msg)?;
|
||||||
|
|
||||||
debug!("message {} successfully moved to folder `{}`", uid, target);
|
debug!("message {} successfully moved to folder `{}`", uid, target);
|
||||||
output.print(format!(
|
output.print(format!(
|
||||||
|
@ -683,7 +683,8 @@ fn msg_matches_send<ImapService: ImapServiceInterface, SmtpService: SmtpServiceI
|
||||||
|
|
||||||
// add the message/msg to the Sent-Mailbox of the user
|
// add the message/msg to the Sent-Mailbox of the user
|
||||||
msg.flags.insert(Flag::Seen);
|
msg.flags.insert(Flag::Seen);
|
||||||
imap.append_msg("Sent", &mut msg)?;
|
let mbox = Mbox::from("Sent");
|
||||||
|
imap.append_msg(&mbox, &mut msg)?;
|
||||||
|
|
||||||
imap.logout()?;
|
imap.logout()?;
|
||||||
|
|
||||||
|
@ -691,7 +692,7 @@ fn msg_matches_send<ImapService: ImapServiceInterface, SmtpService: SmtpServiceI
|
||||||
}
|
}
|
||||||
|
|
||||||
fn msg_matches_save<ImapService: ImapServiceInterface>(
|
fn msg_matches_save<ImapService: ImapServiceInterface>(
|
||||||
mbox: &str,
|
mbox: &Mbox,
|
||||||
matches: &clap::ArgMatches,
|
matches: &clap::ArgMatches,
|
||||||
imap: &mut ImapService,
|
imap: &mut ImapService,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
|
@ -894,7 +895,8 @@ fn msg_interaction<ImapService: ImapServiceInterface, SmtpService: SmtpServiceIn
|
||||||
|
|
||||||
// let the server know, that the user sent a msg
|
// let the server know, that the user sent a msg
|
||||||
msg.flags.insert(Flag::Seen);
|
msg.flags.insert(Flag::Seen);
|
||||||
imap.append_msg("Sent", msg)?;
|
let mbox = Mbox::from("Sent");
|
||||||
|
imap.append_msg(&mbox, msg)?;
|
||||||
|
|
||||||
// remove the draft, since we sent it
|
// remove the draft, since we sent it
|
||||||
input::remove_draft()?;
|
input::remove_draft()?;
|
||||||
|
@ -919,7 +921,8 @@ fn msg_interaction<ImapService: ImapServiceInterface, SmtpService: SmtpServiceIn
|
||||||
|
|
||||||
msg.flags.insert(Flag::Seen);
|
msg.flags.insert(Flag::Seen);
|
||||||
|
|
||||||
match imap.append_msg("Drafts", msg) {
|
let mbox = Mbox::from("Drafts");
|
||||||
|
match imap.append_msg(&mbox, msg) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
input::remove_draft()?;
|
input::remove_draft()?;
|
||||||
output.print("Message successfully saved to Drafts")?;
|
output.print("Message successfully saved to Drafts")?;
|
||||||
|
|
|
@ -7,6 +7,7 @@ use lettre::{
|
||||||
},
|
},
|
||||||
Transport,
|
Transport,
|
||||||
};
|
};
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
use crate::domain::account::entity::Account;
|
use crate::domain::account::entity::Account;
|
||||||
|
|
||||||
|
@ -20,13 +21,6 @@ pub struct SmtpService<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SmtpService<'a> {
|
impl<'a> SmtpService<'a> {
|
||||||
pub fn new(account: &'a Account) -> Result<Self> {
|
|
||||||
Ok(Self {
|
|
||||||
account,
|
|
||||||
transport: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transport(&mut self) -> Result<&SmtpTransport> {
|
fn transport(&mut self) -> Result<&SmtpTransport> {
|
||||||
if let Some(ref transport) = self.transport {
|
if let Some(ref transport) = self.transport {
|
||||||
Ok(transport)
|
Ok(transport)
|
||||||
|
@ -66,3 +60,13 @@ impl<'a> SmtpServiceInterface for SmtpService<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a Account> for SmtpService<'a> {
|
||||||
|
fn from(account: &'a Account) -> Self {
|
||||||
|
debug!("init SMTP service");
|
||||||
|
Self {
|
||||||
|
account,
|
||||||
|
transport: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
48
src/main.rs
48
src/main.rs
|
@ -1,8 +1,7 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap;
|
use clap;
|
||||||
use env_logger;
|
use env_logger;
|
||||||
use log::{debug, trace};
|
use std::{convert::TryFrom, env};
|
||||||
use std::{convert::TryFrom, env, path::PathBuf};
|
|
||||||
|
|
||||||
use himalaya::{
|
use himalaya::{
|
||||||
compl,
|
compl,
|
||||||
|
@ -11,7 +10,8 @@ use himalaya::{
|
||||||
account::entity::Account,
|
account::entity::Account,
|
||||||
config::entity::Config,
|
config::entity::Config,
|
||||||
imap::{self, service::ImapService},
|
imap::{self, service::ImapService},
|
||||||
mbox, msg,
|
mbox::{self, entity::Mbox},
|
||||||
|
msg,
|
||||||
smtp::service::SmtpService,
|
smtp::service::SmtpService,
|
||||||
},
|
},
|
||||||
flag,
|
flag,
|
||||||
|
@ -35,13 +35,13 @@ fn create_app<'a>() -> clap::App<'a, 'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
// Init env logger
|
||||||
env_logger::init_from_env(
|
env_logger::init_from_env(
|
||||||
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "off"),
|
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "off"),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO: put in a `mailto` module
|
||||||
// let raw_args: Vec<String> = env::args().collect();
|
// let raw_args: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
// // This is used if you click on a mailaddress in the webbrowser
|
|
||||||
// if raw_args.len() > 1 && raw_args[1].starts_with("mailto:") {
|
// if raw_args.len() > 1 && raw_args[1].starts_with("mailto:") {
|
||||||
// let config = Config::new(None)?;
|
// let config = Config::new(None)?;
|
||||||
// let account = config.find_account_by_name(None)?.clone();
|
// let account = config.find_account_by_name(None)?.clone();
|
||||||
|
@ -59,41 +59,21 @@ fn main() -> Result<()> {
|
||||||
|
|
||||||
// Check shell completion BEFORE any entity or service initialization.
|
// Check shell completion BEFORE any entity or service initialization.
|
||||||
if let Some(compl::arg::Match::Generate(shell)) = compl::arg::matches(&m)? {
|
if let Some(compl::arg::Match::Generate(shell)) = compl::arg::matches(&m)? {
|
||||||
let app = create_app();
|
return compl::handler::generate(shell, create_app());
|
||||||
compl::handler::generate(shell, app)?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = OutputService::new(m.value_of("output").unwrap())?;
|
let mbox = Mbox::try_from(m.value_of("mailbox"))?;
|
||||||
|
let config = Config::try_from(m.value_of("config"))?;
|
||||||
|
let account = Account::try_from((&config, m.value_of("account")))?;
|
||||||
|
let output = OutputService::try_from(m.value_of("output"))?;
|
||||||
|
let mut imap = ImapService::from((&account, &mbox));
|
||||||
|
let mut smtp = SmtpService::from(&account);
|
||||||
|
|
||||||
debug!("init mbox");
|
// TODO: use same system as compl
|
||||||
let mbox = m.value_of("mailbox").unwrap();
|
|
||||||
debug!("mbox: {}", mbox);
|
|
||||||
|
|
||||||
let config_path: PathBuf = m
|
|
||||||
.value_of("config")
|
|
||||||
.map(|s| s.into())
|
|
||||||
.unwrap_or(Config::path()?);
|
|
||||||
debug!("init config from `{:?}`", config_path);
|
|
||||||
let config = Config::try_from(config_path.clone())?;
|
|
||||||
trace!("{:#?}", config);
|
|
||||||
|
|
||||||
let account_name = m.value_of("account");
|
|
||||||
debug!("init account `{}`", account_name.unwrap_or("default"));
|
|
||||||
let account = Account::try_from((&config, account_name))?;
|
|
||||||
trace!("{:#?}", account);
|
|
||||||
|
|
||||||
debug!("init IMAP service");
|
|
||||||
let mut imap = ImapService::new(&account, &mbox)?;
|
|
||||||
|
|
||||||
debug!("init SMTP service");
|
|
||||||
let mut smtp = SmtpService::new(&account)?;
|
|
||||||
|
|
||||||
debug!("begin matching");
|
|
||||||
let _matched = mbox::cli::matches(&m, &output, &mut imap)?
|
let _matched = mbox::cli::matches(&m, &output, &mut imap)?
|
||||||
|| flag::cli::matches(&m, &mut imap)?
|
|| flag::cli::matches(&m, &mut imap)?
|
||||||
|| imap::cli::matches(&m, &config, &mut imap)?
|
|| imap::cli::matches(&m, &config, &mut imap)?
|
||||||
|| msg::cli::matches(&m, mbox, &account, &output, &mut imap, &mut smtp)?;
|
|| msg::cli::matches(&m, &mbox, &account, &output, &mut imap, &mut smtp)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
use anyhow::{anyhow, Error, Result};
|
use anyhow::{anyhow, Error, Result};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::{fmt, str::FromStr};
|
use std::{
|
||||||
|
convert::{TryFrom, TryInto},
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum OutputFmt {
|
pub enum OutputFmt {
|
||||||
|
@ -9,13 +12,15 @@ pub enum OutputFmt {
|
||||||
Json,
|
Json,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for OutputFmt {
|
impl TryFrom<Option<&str>> for OutputFmt {
|
||||||
type Err = Error;
|
type Error = Error;
|
||||||
fn from_str(slice: &str) -> Result<Self, Self::Err> {
|
|
||||||
match slice {
|
fn try_from(fmt: Option<&str>) -> Result<Self, Self::Error> {
|
||||||
"JSON" | _ if slice.eq_ignore_ascii_case("json") => Ok(Self::Json),
|
match fmt {
|
||||||
"PLAIN" | _ if slice.eq_ignore_ascii_case("plain") => Ok(Self::Plain),
|
Some(slice) if slice.eq_ignore_ascii_case("json") => Ok(Self::Json),
|
||||||
_ => Err(anyhow!("cannot parse output `{}`", slice)),
|
Some(slice) if slice.eq_ignore_ascii_case("plain") => Ok(Self::Plain),
|
||||||
|
None => Ok(Self::Plain),
|
||||||
|
Some(slice) => Err(anyhow!("cannot parse output `{}`", slice)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,9 +60,7 @@ pub struct OutputService {
|
||||||
impl OutputService {
|
impl OutputService {
|
||||||
/// Create a new output-handler by setting the given formatting style.
|
/// Create a new output-handler by setting the given formatting style.
|
||||||
pub fn new(slice: &str) -> Result<Self> {
|
pub fn new(slice: &str) -> Result<Self> {
|
||||||
debug!("init output service");
|
let fmt = OutputFmt::try_from(Some(slice))?;
|
||||||
debug!("output: {}", slice);
|
|
||||||
let fmt = OutputFmt::from_str(slice)?;
|
|
||||||
Ok(Self { fmt })
|
Ok(Self { fmt })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,3 +98,14 @@ impl Default for OutputService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Option<&str>> for OutputService {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from(fmt: Option<&str>) -> Result<Self, Self::Error> {
|
||||||
|
debug!("init output service");
|
||||||
|
debug!("output: `{:?}`", fmt);
|
||||||
|
let fmt = fmt.try_into()?;
|
||||||
|
Ok(Self { fmt })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue