mirror of
https://github.com/soywod/himalaya.git
synced 2024-09-28 20:21:13 +00:00
split idle cmd into notify+watch, remove err when empty result
This commit is contained in:
parent
9d40a7d30f
commit
ef1a22d986
|
@ -28,6 +28,7 @@ pub struct Account {
|
||||||
pub downloads_dir: Option<PathBuf>,
|
pub downloads_dir: Option<PathBuf>,
|
||||||
pub signature: Option<String>,
|
pub signature: Option<String>,
|
||||||
pub default_page_size: Option<usize>,
|
pub default_page_size: Option<usize>,
|
||||||
|
pub watch_cmds: Option<Vec<String>>,
|
||||||
|
|
||||||
// Specific
|
// Specific
|
||||||
pub default: Option<bool>,
|
pub default: Option<bool>,
|
||||||
|
@ -118,10 +119,7 @@ pub struct Config {
|
||||||
pub notify_cmd: Option<String>,
|
pub notify_cmd: Option<String>,
|
||||||
pub signature: Option<String>,
|
pub signature: Option<String>,
|
||||||
pub default_page_size: Option<usize>,
|
pub default_page_size: Option<usize>,
|
||||||
|
pub watch_cmds: Option<Vec<String>>,
|
||||||
#[serde(default)]
|
|
||||||
pub idle_hook_cmds: Vec<String>,
|
|
||||||
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub accounts: HashMap<String, Account>,
|
pub accounts: HashMap<String, Account>,
|
||||||
}
|
}
|
||||||
|
@ -246,15 +244,21 @@ impl Config {
|
||||||
.to_owned()
|
.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exec_idle_hooks(&self) -> Result<()> {
|
pub fn exec_watch_cmds(&self, account: &Account) -> Result<()> {
|
||||||
let cmds = self.idle_hook_cmds.to_owned();
|
let cmds = account
|
||||||
|
.watch_cmds
|
||||||
|
.as_ref()
|
||||||
|
.or_else(|| self.watch_cmds.as_ref())
|
||||||
|
.map(|cmds| cmds.to_owned())
|
||||||
|
.unwrap_or_default();
|
||||||
|
debug!("cmds: {:?}", cmds);
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
debug!("batch execution of {} cmd(s)", cmds.len());
|
debug!("batch execution of {} cmd(s)", cmds.len());
|
||||||
cmds.iter().for_each(|cmd| {
|
cmds.iter().for_each(|cmd| {
|
||||||
debug!("execute cmd {:?}", cmd);
|
debug!("running command {:?}…", cmd);
|
||||||
let res = run_cmd(&cmd);
|
let res = run_cmd(cmd);
|
||||||
debug!("res: {:?}", res);
|
debug!("{:?}", res);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -12,15 +12,53 @@ error_chain! {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn imap_subcmds<'a>() -> Vec<clap::App<'a, 'a>> {
|
pub fn imap_subcmds<'a>() -> Vec<clap::App<'a, 'a>> {
|
||||||
vec![clap::SubCommand::with_name("idle").about("Spawns a blocking idle daemon")]
|
vec![
|
||||||
|
clap::SubCommand::with_name("notify")
|
||||||
|
.about("Notifies when new messages arrive in the given mailbox")
|
||||||
|
.aliases(&["idle"])
|
||||||
|
.arg(
|
||||||
|
clap::Arg::with_name("keepalive")
|
||||||
|
.help("Specifies the keepalive duration")
|
||||||
|
.short("k")
|
||||||
|
.long("keepalive")
|
||||||
|
.value_name("SECS")
|
||||||
|
.default_value("500"),
|
||||||
|
),
|
||||||
|
clap::SubCommand::with_name("watch")
|
||||||
|
.about("Watches IMAP server changes")
|
||||||
|
.arg(
|
||||||
|
clap::Arg::with_name("keepalive")
|
||||||
|
.help("Specifies the keepalive duration")
|
||||||
|
.short("k")
|
||||||
|
.long("keepalive")
|
||||||
|
.value_name("SECS")
|
||||||
|
.default_value("500"),
|
||||||
|
),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn imap_matches(app: &App) -> Result<bool> {
|
pub fn imap_matches(app: &App) -> Result<bool> {
|
||||||
if let Some(_) = app.arg_matches.subcommand_matches("idle") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("notify") {
|
||||||
debug!("idle command matched");
|
debug!("notify command matched");
|
||||||
|
|
||||||
|
let keepalive = clap::value_t_or_exit!(matches.value_of("keepalive"), u64);
|
||||||
|
debug!("keepalive: {}", &keepalive);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&app.account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
imap_conn.idle(&app.config, &app.mbox)?;
|
imap_conn.notify(&app, keepalive)?;
|
||||||
|
|
||||||
|
imap_conn.logout();
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(matches) = app.arg_matches.subcommand_matches("watch") {
|
||||||
|
debug!("watch command matched");
|
||||||
|
|
||||||
|
let keepalive = clap::value_t_or_exit!(matches.value_of("keepalive"), u64);
|
||||||
|
debug!("keepalive: {}", &keepalive);
|
||||||
|
|
||||||
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
|
imap_conn.watch(&app, keepalive)?;
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
|
|
|
@ -4,11 +4,7 @@ use log::{debug, trace};
|
||||||
use native_tls::{self, TlsConnector, TlsStream};
|
use native_tls::{self, TlsConnector, TlsStream};
|
||||||
use std::{collections::HashSet, iter::FromIterator, net::TcpStream};
|
use std::{collections::HashSet, iter::FromIterator, net::TcpStream};
|
||||||
|
|
||||||
use crate::{
|
use crate::{app::App, config::model::Account, flag::model::Flag, msg::model::Msg};
|
||||||
config::model::{Account, Config},
|
|
||||||
flag::model::Flag,
|
|
||||||
msg::model::Msg,
|
|
||||||
};
|
|
||||||
|
|
||||||
error_chain! {
|
error_chain! {
|
||||||
links {
|
links {
|
||||||
|
@ -22,30 +18,30 @@ pub struct ImapConnector<'a> {
|
||||||
pub sess: imap::Session<TlsStream<TcpStream>>,
|
pub sess: imap::Session<TlsStream<TcpStream>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ic> ImapConnector<'ic> {
|
impl<'a> ImapConnector<'a> {
|
||||||
pub fn new(account: &'ic Account) -> Result<Self> {
|
pub fn new(account: &'a Account) -> Result<Self> {
|
||||||
debug!("create TLS builder");
|
debug!("create TLS builder");
|
||||||
let insecure = account.imap_insecure();
|
let insecure = account.imap_insecure();
|
||||||
let tls = TlsConnector::builder()
|
let tls = TlsConnector::builder()
|
||||||
.danger_accept_invalid_certs(insecure)
|
.danger_accept_invalid_certs(insecure)
|
||||||
.danger_accept_invalid_hostnames(insecure)
|
.danger_accept_invalid_hostnames(insecure)
|
||||||
.build()
|
.build()
|
||||||
.chain_err(|| "Cannot create TLS connector")?;
|
.chain_err(|| "Could not create TLS connector")?;
|
||||||
|
|
||||||
debug!("create client");
|
debug!("create client");
|
||||||
let client = if account.imap_starttls() {
|
let client = if account.imap_starttls() {
|
||||||
imap::connect_starttls(account.imap_addr(), &account.imap_host, &tls)
|
imap::connect_starttls(account.imap_addr(), &account.imap_host, &tls)
|
||||||
.chain_err(|| "Cannot connect using STARTTLS")
|
.chain_err(|| "Could not connect using STARTTLS")
|
||||||
} else {
|
} else {
|
||||||
imap::connect(account.imap_addr(), &account.imap_host, &tls)
|
imap::connect(account.imap_addr(), &account.imap_host, &tls)
|
||||||
.chain_err(|| "Cannot connect using TLS")
|
.chain_err(|| "Could not connect using TLS")
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
debug!("create session");
|
debug!("create session");
|
||||||
let sess = client
|
let sess = client
|
||||||
.login(&account.imap_login, &account.imap_passwd()?)
|
.login(&account.imap_login, &account.imap_passwd()?)
|
||||||
.map_err(|res| res.0)
|
.map_err(|res| res.0)
|
||||||
.chain_err(|| "Cannot login to IMAP server")?;
|
.chain_err(|| "Could not login to IMAP server")?;
|
||||||
|
|
||||||
Ok(Self { account, sess })
|
Ok(Self { account, sess })
|
||||||
}
|
}
|
||||||
|
@ -60,11 +56,11 @@ impl<'ic> ImapConnector<'ic> {
|
||||||
pub fn set_flags(&mut self, mbox: &str, uid_seq: &str, flags: &str) -> Result<()> {
|
pub fn set_flags(&mut self, mbox: &str, uid_seq: &str, flags: &str) -> Result<()> {
|
||||||
self.sess
|
self.sess
|
||||||
.select(mbox)
|
.select(mbox)
|
||||||
.chain_err(|| format!("Cannot select mailbox `{}`", mbox))?;
|
.chain_err(|| format!("Could not select mailbox `{}`", mbox))?;
|
||||||
|
|
||||||
self.sess
|
self.sess
|
||||||
.uid_store(uid_seq, format!("FLAGS ({})", flags))
|
.uid_store(uid_seq, format!("FLAGS ({})", flags))
|
||||||
.chain_err(|| format!("Cannot set flags `{}`", &flags))?;
|
.chain_err(|| format!("Could not set flags `{}`", &flags))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -72,11 +68,11 @@ impl<'ic> ImapConnector<'ic> {
|
||||||
pub fn add_flags(&mut self, mbox: &str, uid_seq: &str, flags: &str) -> Result<()> {
|
pub fn add_flags(&mut self, mbox: &str, uid_seq: &str, flags: &str) -> Result<()> {
|
||||||
self.sess
|
self.sess
|
||||||
.select(mbox)
|
.select(mbox)
|
||||||
.chain_err(|| format!("Cannot select mailbox `{}`", mbox))?;
|
.chain_err(|| format!("Could not select mailbox `{}`", mbox))?;
|
||||||
|
|
||||||
self.sess
|
self.sess
|
||||||
.uid_store(uid_seq, format!("+FLAGS ({})", flags))
|
.uid_store(uid_seq, format!("+FLAGS ({})", flags))
|
||||||
.chain_err(|| format!("Cannot add flags `{}`", &flags))?;
|
.chain_err(|| format!("Could not add flags `{}`", &flags))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -84,11 +80,11 @@ impl<'ic> ImapConnector<'ic> {
|
||||||
pub fn remove_flags(&mut self, mbox: &str, uid_seq: &str, flags: &str) -> Result<()> {
|
pub fn remove_flags(&mut self, mbox: &str, uid_seq: &str, flags: &str) -> Result<()> {
|
||||||
self.sess
|
self.sess
|
||||||
.select(mbox)
|
.select(mbox)
|
||||||
.chain_err(|| format!("Cannot select mailbox `{}`", mbox))?;
|
.chain_err(|| format!("Could not select mailbox `{}`", mbox))?;
|
||||||
|
|
||||||
self.sess
|
self.sess
|
||||||
.uid_store(uid_seq, format!("-FLAGS ({})", flags))
|
.uid_store(uid_seq, format!("-FLAGS ({})", flags))
|
||||||
.chain_err(|| format!("Cannot remove flags `{}`", &flags))?;
|
.chain_err(|| format!("Could not remove flags `{}`", &flags))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -106,11 +102,11 @@ impl<'ic> ImapConnector<'ic> {
|
||||||
Ok(uids)
|
Ok(uids)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn idle(&mut self, config: &Config, mbox: &str) -> Result<()> {
|
pub fn notify(&mut self, app: &App, keepalive: u64) -> Result<()> {
|
||||||
debug!("examine mailbox: {}", mbox);
|
debug!("examine mailbox: {}", &app.mbox);
|
||||||
self.sess
|
self.sess
|
||||||
.examine(mbox)
|
.examine(&app.mbox)
|
||||||
.chain_err(|| format!("Could not examine mailbox `{}`", mbox))?;
|
.chain_err(|| format!("Could not examine mailbox `{}`", &app.mbox))?;
|
||||||
|
|
||||||
debug!("init messages hashset");
|
debug!("init messages hashset");
|
||||||
let mut msgs_set: HashSet<u32> =
|
let mut msgs_set: HashSet<u32> =
|
||||||
|
@ -122,7 +118,7 @@ impl<'ic> ImapConnector<'ic> {
|
||||||
self.sess
|
self.sess
|
||||||
.idle()
|
.idle()
|
||||||
.and_then(|mut idle| {
|
.and_then(|mut idle| {
|
||||||
idle.set_keepalive(std::time::Duration::new(300, 0));
|
idle.set_keepalive(std::time::Duration::new(keepalive, 0));
|
||||||
idle.wait_keepalive()
|
idle.wait_keepalive()
|
||||||
})
|
})
|
||||||
.chain_err(|| "Could not start the idle mode")?;
|
.chain_err(|| "Could not start the idle mode")?;
|
||||||
|
@ -151,7 +147,7 @@ impl<'ic> ImapConnector<'ic> {
|
||||||
let uid = fetch.uid.ok_or_else(|| {
|
let uid = fetch.uid.ok_or_else(|| {
|
||||||
format!("Could not retrieve message {}'s UID", fetch.message)
|
format!("Could not retrieve message {}'s UID", fetch.message)
|
||||||
})?;
|
})?;
|
||||||
config.run_notify_cmd(&msg.subject, &msg.sender)?;
|
app.config.run_notify_cmd(&msg.subject, &msg.sender)?;
|
||||||
debug!("notify message: {}", uid);
|
debug!("notify message: {}", uid);
|
||||||
trace!("message: {:?}", msg);
|
trace!("message: {:?}", msg);
|
||||||
|
|
||||||
|
@ -161,7 +157,26 @@ impl<'ic> ImapConnector<'ic> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config.exec_idle_hooks()?;
|
debug!("end loop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn watch(&mut self, app: &App, keepalive: u64) -> Result<()> {
|
||||||
|
debug!("examine mailbox: {}", &app.mbox);
|
||||||
|
self.sess
|
||||||
|
.examine(&app.mbox)
|
||||||
|
.chain_err(|| format!("Could not examine mailbox `{}`", &app.mbox))?;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
debug!("begin loop");
|
||||||
|
self.sess
|
||||||
|
.idle()
|
||||||
|
.and_then(|mut idle| {
|
||||||
|
idle.set_keepalive(std::time::Duration::new(keepalive, 0));
|
||||||
|
idle.wait_keepalive()
|
||||||
|
})
|
||||||
|
.chain_err(|| "Could not start the idle mode")?;
|
||||||
|
app.config.exec_watch_cmds(&app.account)?;
|
||||||
debug!("end loop");
|
debug!("end loop");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,7 +185,7 @@ impl<'ic> ImapConnector<'ic> {
|
||||||
let names = self
|
let names = self
|
||||||
.sess
|
.sess
|
||||||
.list(Some(""), Some("*"))
|
.list(Some(""), Some("*"))
|
||||||
.chain_err(|| "Cannot list mailboxes")?;
|
.chain_err(|| "Could not list mailboxes")?;
|
||||||
|
|
||||||
Ok(names)
|
Ok(names)
|
||||||
}
|
}
|
||||||
|
@ -180,15 +195,15 @@ impl<'ic> ImapConnector<'ic> {
|
||||||
mbox: &str,
|
mbox: &str,
|
||||||
page_size: &usize,
|
page_size: &usize,
|
||||||
page: &usize,
|
page: &usize,
|
||||||
) -> Result<imap::types::ZeroCopy<Vec<imap::types::Fetch>>> {
|
) -> Result<Option<imap::types::ZeroCopy<Vec<imap::types::Fetch>>>> {
|
||||||
let last_seq = self
|
let last_seq = self
|
||||||
.sess
|
.sess
|
||||||
.select(mbox)
|
.select(mbox)
|
||||||
.chain_err(|| format!("Cannot select mailbox `{}`", mbox))?
|
.chain_err(|| format!("Could not select mailbox `{}`", mbox))?
|
||||||
.exists as i64;
|
.exists as i64;
|
||||||
|
|
||||||
if last_seq == 0 {
|
if last_seq == 0 {
|
||||||
return Err(format!("The `{}` mailbox is empty", mbox).into());
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add tests, improve error management when empty page
|
// TODO: add tests, improve error management when empty page
|
||||||
|
@ -204,9 +219,9 @@ impl<'ic> ImapConnector<'ic> {
|
||||||
let fetches = self
|
let fetches = self
|
||||||
.sess
|
.sess
|
||||||
.fetch(range, "(UID FLAGS ENVELOPE INTERNALDATE)")
|
.fetch(range, "(UID FLAGS ENVELOPE INTERNALDATE)")
|
||||||
.chain_err(|| "Cannot fetch messages")?;
|
.chain_err(|| "Could not fetch messages")?;
|
||||||
|
|
||||||
Ok(fetches)
|
Ok(Some(fetches))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn search_msgs(
|
pub fn search_msgs(
|
||||||
|
@ -215,45 +230,46 @@ impl<'ic> ImapConnector<'ic> {
|
||||||
query: &str,
|
query: &str,
|
||||||
page_size: &usize,
|
page_size: &usize,
|
||||||
page: &usize,
|
page: &usize,
|
||||||
) -> Result<imap::types::ZeroCopy<Vec<imap::types::Fetch>>> {
|
) -> Result<Option<imap::types::ZeroCopy<Vec<imap::types::Fetch>>>> {
|
||||||
self.sess
|
self.sess
|
||||||
.select(mbox)
|
.select(mbox)
|
||||||
.chain_err(|| format!("Cannot select mailbox `{}`", mbox))?;
|
.chain_err(|| format!("Could not select mailbox `{}`", mbox))?;
|
||||||
|
|
||||||
let begin = page * page_size;
|
let begin = page * page_size;
|
||||||
let end = begin + (page_size - 1);
|
let end = begin + (page_size - 1);
|
||||||
let uids = self
|
let uids: Vec<String> = self
|
||||||
.sess
|
.sess
|
||||||
.search(query)
|
.search(query)
|
||||||
.chain_err(|| format!("Cannot search in `{}` with query `{}`", mbox, query))?
|
.chain_err(|| format!("Could not search in `{}` with query `{}`", mbox, query))?
|
||||||
.iter()
|
.iter()
|
||||||
.map(|seq| seq.to_string())
|
.map(|seq| seq.to_string())
|
||||||
.collect::<Vec<_>>();
|
.collect();
|
||||||
let range = uids[begin..end.min(uids.len())].join(",");
|
|
||||||
|
|
||||||
|
if uids.is_empty() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let range = uids[begin..end.min(uids.len())].join(",");
|
||||||
let fetches = self
|
let fetches = self
|
||||||
.sess
|
.sess
|
||||||
.fetch(&range, "(UID FLAGS ENVELOPE INTERNALDATE)")
|
.fetch(&range, "(UID FLAGS ENVELOPE INTERNALDATE)")
|
||||||
.chain_err(|| format!("Cannot fetch range `{}`", &range))?;
|
.chain_err(|| format!("Could not fetch range `{}`", &range))?;
|
||||||
// .iter()
|
|
||||||
// .map(|fetch| Msg::from(fetch))
|
|
||||||
// .collect::<Vec<_>>();
|
|
||||||
|
|
||||||
Ok(fetches)
|
Ok(Some(fetches))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_msg(&mut self, mbox: &str, uid: &str) -> Result<Vec<u8>> {
|
pub fn read_msg(&mut self, mbox: &str, uid: &str) -> Result<Vec<u8>> {
|
||||||
self.sess
|
self.sess
|
||||||
.select(mbox)
|
.select(mbox)
|
||||||
.chain_err(|| format!("Cannot select mailbox `{}`", mbox))?;
|
.chain_err(|| format!("Could not select mailbox `{}`", mbox))?;
|
||||||
|
|
||||||
match self
|
match self
|
||||||
.sess
|
.sess
|
||||||
.uid_fetch(uid, "(FLAGS BODY[])")
|
.uid_fetch(uid, "(FLAGS BODY[])")
|
||||||
.chain_err(|| "Cannot fetch bodies")?
|
.chain_err(|| "Could not fetch bodies")?
|
||||||
.first()
|
.first()
|
||||||
{
|
{
|
||||||
None => Err(format!("Cannot find message `{}`", uid).into()),
|
None => Err(format!("Could not find message `{}`", uid).into()),
|
||||||
Some(fetch) => Ok(fetch.body().unwrap_or(&[]).to_vec()),
|
Some(fetch) => Ok(fetch.body().unwrap_or(&[]).to_vec()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,7 +277,7 @@ impl<'ic> ImapConnector<'ic> {
|
||||||
pub fn append_msg(&mut self, mbox: &str, msg: &[u8], flags: &[Flag]) -> Result<()> {
|
pub fn append_msg(&mut self, mbox: &str, msg: &[u8], flags: &[Flag]) -> Result<()> {
|
||||||
self.sess
|
self.sess
|
||||||
.append_with_flags(mbox, msg, flags)
|
.append_with_flags(mbox, msg, flags)
|
||||||
.chain_err(|| format!("Cannot append message to `{}`", mbox))?;
|
.chain_err(|| format!("Could not append message to `{}`", mbox))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,7 +187,12 @@ pub fn msg_matches(app: &App) -> Result<bool> {
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&app.account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msgs = imap_conn.list_msgs(&app.mbox, &page_size, &page)?;
|
let msgs = imap_conn.list_msgs(&app.mbox, &page_size, &page)?;
|
||||||
let msgs = Msgs::from(&msgs);
|
let msgs = if let Some(ref fetches) = msgs {
|
||||||
|
Msgs::from(fetches)
|
||||||
|
} else {
|
||||||
|
Msgs::new()
|
||||||
|
};
|
||||||
|
|
||||||
trace!("messages: {:?}", msgs);
|
trace!("messages: {:?}", msgs);
|
||||||
app.output.print(msgs);
|
app.output.print(msgs);
|
||||||
|
|
||||||
|
@ -238,7 +243,11 @@ pub fn msg_matches(app: &App) -> Result<bool> {
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&app.account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msgs = imap_conn.search_msgs(&app.mbox, &query, &page_size, &page)?;
|
let msgs = imap_conn.search_msgs(&app.mbox, &query, &page_size, &page)?;
|
||||||
let msgs = Msgs::from(&msgs);
|
let msgs = if let Some(ref fetches) = msgs {
|
||||||
|
Msgs::from(fetches)
|
||||||
|
} else {
|
||||||
|
Msgs::new()
|
||||||
|
};
|
||||||
trace!("messages: {:?}", msgs);
|
trace!("messages: {:?}", msgs);
|
||||||
app.output.print(msgs);
|
app.output.print(msgs);
|
||||||
|
|
||||||
|
@ -637,7 +646,11 @@ pub fn msg_matches(app: &App) -> Result<bool> {
|
||||||
let mut imap_conn = ImapConnector::new(&app.account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msgs =
|
let msgs =
|
||||||
imap_conn.list_msgs(&app.mbox, &app.config.default_page_size(&app.account), &0)?;
|
imap_conn.list_msgs(&app.mbox, &app.config.default_page_size(&app.account), &0)?;
|
||||||
let msgs = Msgs::from(&msgs);
|
let msgs = if let Some(ref fetches) = msgs {
|
||||||
|
Msgs::from(fetches)
|
||||||
|
} else {
|
||||||
|
Msgs::new()
|
||||||
|
};
|
||||||
app.output.print(msgs);
|
app.output.print(msgs);
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
|
|
|
@ -80,7 +80,6 @@ impl<'a> Attachments {
|
||||||
.get_headers()
|
.get_headers()
|
||||||
.get_first_value("content-type")
|
.get_first_value("content-type")
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
if !ctype.starts_with("text") {
|
if !ctype.starts_with("text") {
|
||||||
self.0.push(Attachment::from_part(part));
|
self.0.push(Attachment::from_part(part));
|
||||||
}
|
}
|
||||||
|
@ -646,15 +645,21 @@ impl<'m> Table for Msg<'m> {
|
||||||
// Msgs
|
// Msgs
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct Msgs<'m>(pub Vec<Msg<'m>>);
|
pub struct Msgs<'a>(pub Vec<Msg<'a>>);
|
||||||
|
|
||||||
impl<'m> From<&'m imap::types::ZeroCopy<Vec<imap::types::Fetch>>> for Msgs<'m> {
|
impl<'a> From<&'a imap::types::ZeroCopy<Vec<imap::types::Fetch>>> for Msgs<'a> {
|
||||||
fn from(fetches: &'m imap::types::ZeroCopy<Vec<imap::types::Fetch>>) -> Self {
|
fn from(fetches: &'a imap::types::ZeroCopy<Vec<imap::types::Fetch>>) -> Self {
|
||||||
Self(fetches.iter().rev().map(Msg::from).collect::<Vec<_>>())
|
Self(fetches.iter().rev().map(Msg::from).collect::<Vec<_>>())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'m> fmt::Display for Msgs<'m> {
|
impl Msgs<'_> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(vec![])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Msgs<'_> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
writeln!(f, "\n{}", Table::render(&self.0))
|
writeln!(f, "\n{}", Table::render(&self.0))
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,7 +256,7 @@ where
|
||||||
fn render(items: &[Self]) -> String {
|
fn render(items: &[Self]) -> String {
|
||||||
Self::build(items)
|
Self::build(items)
|
||||||
.iter()
|
.iter()
|
||||||
.map(|row| row.join(&Cell::new("|").ext(8).to_string()))
|
.map(|row| row.join(&Cell::new("│").ext(8).to_string()))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n")
|
.join("\n")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue