mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-20 07:01:12 +00:00
add id mapper to notmuch backend
This commit is contained in:
parent
ad1f97faed
commit
6606bd9f16
|
@ -3,7 +3,7 @@ use std::{convert::TryInto, fs};
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::{Backend, NotmuchEnvelopes, NotmuchMbox, NotmuchMboxes},
|
backends::{Backend, IdMapper, NotmuchEnvelopes, NotmuchMbox, NotmuchMboxes},
|
||||||
config::{AccountConfig, NotmuchBackendConfig},
|
config::{AccountConfig, NotmuchBackendConfig},
|
||||||
mbox::Mboxes,
|
mbox::Mboxes,
|
||||||
msg::{Envelopes, Msg},
|
msg::{Envelopes, Msg},
|
||||||
|
@ -11,6 +11,7 @@ use crate::{
|
||||||
|
|
||||||
pub struct NotmuchBackend<'a> {
|
pub struct NotmuchBackend<'a> {
|
||||||
account_config: &'a AccountConfig,
|
account_config: &'a AccountConfig,
|
||||||
|
notmuch_config: &'a NotmuchBackendConfig,
|
||||||
db: notmuch::Database,
|
db: notmuch::Database,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@ impl<'a> NotmuchBackend<'a> {
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
account_config,
|
account_config,
|
||||||
|
notmuch_config,
|
||||||
db: notmuch::Database::open(
|
db: notmuch::Database::open(
|
||||||
notmuch_config.notmuch_database_dir.clone(),
|
notmuch_config.notmuch_database_dir.clone(),
|
||||||
notmuch::DatabaseMode::ReadWrite,
|
notmuch::DatabaseMode::ReadWrite,
|
||||||
|
@ -31,6 +33,64 @@ impl<'a> NotmuchBackend<'a> {
|
||||||
))?,
|
))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _search_envelopes(
|
||||||
|
&mut self,
|
||||||
|
query: &str,
|
||||||
|
virt_mbox: &str,
|
||||||
|
page_size: usize,
|
||||||
|
page: usize,
|
||||||
|
) -> Result<Box<dyn Envelopes>> {
|
||||||
|
// Gets envelopes matching the given Notmuch query.
|
||||||
|
let query_builder = self
|
||||||
|
.db
|
||||||
|
.create_query(query)
|
||||||
|
.context(format!("cannot create notmuch query from {:?}", query))?;
|
||||||
|
let mut envelopes: NotmuchEnvelopes = query_builder
|
||||||
|
.search_messages()
|
||||||
|
.context(format!(
|
||||||
|
"cannot find notmuch envelopes from query {:?}",
|
||||||
|
query
|
||||||
|
))?
|
||||||
|
.try_into()
|
||||||
|
.context(format!(
|
||||||
|
"cannot parse notmuch envelopes from query {:?}",
|
||||||
|
query
|
||||||
|
))?;
|
||||||
|
|
||||||
|
// Calculates pagination boundaries.
|
||||||
|
let page_begin = page * page_size;
|
||||||
|
if page_begin > envelopes.len() {
|
||||||
|
return Err(anyhow!(format!(
|
||||||
|
"cannot find notmuch envelopes at page {:?} (out of bounds)",
|
||||||
|
page_begin + 1,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let page_end = envelopes.len().min(page_begin + page_size);
|
||||||
|
|
||||||
|
// Sorts envelopes by most recent date.
|
||||||
|
envelopes.sort_by(|a, b| b.date.partial_cmp(&a.date).unwrap());
|
||||||
|
|
||||||
|
// Applies pagination boundaries.
|
||||||
|
envelopes.0 = envelopes[page_begin..page_end].to_owned();
|
||||||
|
|
||||||
|
// Appends id <=> hash entries to the id mapper cache file.
|
||||||
|
let short_hash_len = {
|
||||||
|
let mut mapper = IdMapper::new(&self.notmuch_config.notmuch_database_dir)?;
|
||||||
|
let entries = envelopes
|
||||||
|
.iter()
|
||||||
|
.map(|env| (env.hash.to_owned(), env.id.to_owned()))
|
||||||
|
.collect();
|
||||||
|
mapper.append(entries)?
|
||||||
|
};
|
||||||
|
|
||||||
|
// Shorten envelopes hash.
|
||||||
|
envelopes
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|env| env.hash = env.hash[0..short_hash_len].to_owned());
|
||||||
|
|
||||||
|
Ok(Box::new(envelopes))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Backend<'a> for NotmuchBackend<'a> {
|
impl<'a> Backend<'a> for NotmuchBackend<'a> {
|
||||||
|
@ -55,81 +115,44 @@ impl<'a> Backend<'a> for NotmuchBackend<'a> {
|
||||||
|
|
||||||
fn get_envelopes(
|
fn get_envelopes(
|
||||||
&mut self,
|
&mut self,
|
||||||
mbox: &str,
|
virt_mbox: &str,
|
||||||
page_size: usize,
|
page_size: usize,
|
||||||
page: usize,
|
page: usize,
|
||||||
) -> Result<Box<dyn Envelopes>> {
|
) -> Result<Box<dyn Envelopes>> {
|
||||||
let query = self
|
let query = self
|
||||||
.account_config
|
.account_config
|
||||||
.mailboxes
|
.mailboxes
|
||||||
.get(mbox)
|
.get(virt_mbox)
|
||||||
.map(|s| s.as_str())
|
.map(|s| s.as_str())
|
||||||
.unwrap_or("all");
|
.unwrap_or("all");
|
||||||
let query_builder = self
|
self._search_envelopes(query, virt_mbox, page_size, page)
|
||||||
.db
|
|
||||||
.create_query(query)
|
|
||||||
.context("cannot create notmuch query")?;
|
|
||||||
let mut envelopes: NotmuchEnvelopes = query_builder
|
|
||||||
.search_messages()
|
|
||||||
.context(format!(
|
|
||||||
"cannot find notmuch envelopes with query {:?}",
|
|
||||||
query
|
|
||||||
))?
|
|
||||||
.try_into()?;
|
|
||||||
envelopes.sort_by(|a, b| b.date.partial_cmp(&a.date).unwrap());
|
|
||||||
let page_begin = page * page_size;
|
|
||||||
if page_begin > envelopes.len() {
|
|
||||||
return Err(anyhow!(format!(
|
|
||||||
"cannot find notmuch envelopes at page {:?} (out of bounds)",
|
|
||||||
page_begin + 1,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
let page_end = envelopes.len().min(page_begin + page_size);
|
|
||||||
envelopes.0 = envelopes[page_begin..page_end].to_owned();
|
|
||||||
Ok(Box::new(envelopes))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_envelopes(
|
fn search_envelopes(
|
||||||
&mut self,
|
&mut self,
|
||||||
_mbox: &str,
|
virt_mbox: &str,
|
||||||
query: &str,
|
query: &str,
|
||||||
_sort: &str,
|
_sort: &str,
|
||||||
page_size: usize,
|
page_size: usize,
|
||||||
page: usize,
|
page: usize,
|
||||||
) -> Result<Box<dyn Envelopes>> {
|
) -> Result<Box<dyn Envelopes>> {
|
||||||
let query_builder = self
|
self._search_envelopes(query, virt_mbox, page_size, page)
|
||||||
.db
|
|
||||||
.create_query(query)
|
|
||||||
.context("cannot create notmuch query")?;
|
|
||||||
let mut envelopes: NotmuchEnvelopes = query_builder
|
|
||||||
.search_messages()
|
|
||||||
.context(format!(
|
|
||||||
"cannot find notmuch envelopes with query {:?}",
|
|
||||||
query
|
|
||||||
))?
|
|
||||||
.try_into()?;
|
|
||||||
// TODO: use sort from parameters instead
|
|
||||||
envelopes.sort_by(|a, b| b.date.partial_cmp(&a.date).unwrap());
|
|
||||||
let page_begin = page * page_size;
|
|
||||||
if page_begin > envelopes.len() {
|
|
||||||
return Err(anyhow!(format!(
|
|
||||||
"cannot find notmuch envelopes at page {:?} (out of bounds)",
|
|
||||||
page_begin + 1,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
let page_end = envelopes.len().min(page_begin + page_size);
|
|
||||||
envelopes.0 = envelopes[page_begin..page_end].to_owned();
|
|
||||||
Ok(Box::new(envelopes))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_msg(&mut self, _mbox: &str, _msg: &[u8], _flags: &str) -> Result<Box<dyn ToString>> {
|
fn add_msg(&mut self, _mbox: &str, _msg: &[u8], _flags: &str) -> Result<Box<dyn ToString>> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_msg(&mut self, _mbox: &str, id: &str) -> Result<Msg> {
|
fn get_msg(&mut self, _mbox: &str, short_hash: &str) -> Result<Msg> {
|
||||||
|
let id = IdMapper::new(&self.notmuch_config.notmuch_database_dir)?
|
||||||
|
.find(short_hash)
|
||||||
|
.context(format!(
|
||||||
|
"cannot get notmuch message from short hash {:?}",
|
||||||
|
short_hash
|
||||||
|
))?;
|
||||||
let msg_filepath = self
|
let msg_filepath = self
|
||||||
.db
|
.db
|
||||||
.find_message(id)
|
.find_message(&id)
|
||||||
.context(format!("cannot find notmuch message {:?}", id))?
|
.context(format!("cannot find notmuch message {:?}", id))?
|
||||||
.ok_or_else(|| anyhow!("cannot find notmuch message {:?}", id))?
|
.ok_or_else(|| anyhow!("cannot find notmuch message {:?}", id))?
|
||||||
.filename()
|
.filename()
|
||||||
|
@ -148,10 +171,16 @@ impl<'a> Backend<'a> for NotmuchBackend<'a> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn del_msg(&mut self, _mbox: &str, id: &str) -> Result<()> {
|
fn del_msg(&mut self, _mbox: &str, short_hash: &str) -> Result<()> {
|
||||||
|
let id = IdMapper::new(&self.notmuch_config.notmuch_database_dir)?
|
||||||
|
.find(short_hash)
|
||||||
|
.context(format!(
|
||||||
|
"cannot get notmuch message from short hash {:?}",
|
||||||
|
short_hash
|
||||||
|
))?;
|
||||||
let msg_filepath = self
|
let msg_filepath = self
|
||||||
.db
|
.db
|
||||||
.find_message(id)
|
.find_message(&id)
|
||||||
.context(format!("cannot find notmuch message {:?}", id))?
|
.context(format!("cannot find notmuch message {:?}", id))?
|
||||||
.ok_or_else(|| anyhow!("cannot find notmuch message {:?}", id))?
|
.ok_or_else(|| anyhow!("cannot find notmuch message {:?}", id))?
|
||||||
.filename()
|
.filename()
|
||||||
|
|
|
@ -51,6 +51,9 @@ pub struct NotmuchEnvelope {
|
||||||
/// Represents the id of the message.
|
/// Represents the id of the message.
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
|
||||||
|
/// Represents the MD5 hash of the message id.
|
||||||
|
pub hash: String,
|
||||||
|
|
||||||
/// Represents the tags of the message.
|
/// Represents the tags of the message.
|
||||||
pub flags: Vec<String>,
|
pub flags: Vec<String>,
|
||||||
|
|
||||||
|
@ -67,7 +70,7 @@ pub struct NotmuchEnvelope {
|
||||||
impl Table for NotmuchEnvelope {
|
impl Table for NotmuchEnvelope {
|
||||||
fn head() -> Row {
|
fn head() -> Row {
|
||||||
Row::new()
|
Row::new()
|
||||||
.cell(Cell::new("ID").bold().underline().white())
|
.cell(Cell::new("HASH").bold().underline().white())
|
||||||
.cell(Cell::new("FLAGS").bold().underline().white())
|
.cell(Cell::new("FLAGS").bold().underline().white())
|
||||||
.cell(Cell::new("SUBJECT").shrinkable().bold().underline().white())
|
.cell(Cell::new("SUBJECT").shrinkable().bold().underline().white())
|
||||||
.cell(Cell::new("SENDER").bold().underline().white())
|
.cell(Cell::new("SENDER").bold().underline().white())
|
||||||
|
@ -75,14 +78,14 @@ impl Table for NotmuchEnvelope {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn row(&self) -> Row {
|
fn row(&self) -> Row {
|
||||||
let id = self.id.to_string();
|
let hash = self.hash.to_string();
|
||||||
let unseen = !self.flags.contains(&String::from("unread"));
|
let unseen = !self.flags.contains(&String::from("unread"));
|
||||||
let flags = String::new();
|
let flags = String::new();
|
||||||
let subject = &self.subject;
|
let subject = &self.subject;
|
||||||
let sender = &self.sender;
|
let sender = &self.sender;
|
||||||
let date = &self.date;
|
let date = &self.date;
|
||||||
Row::new()
|
Row::new()
|
||||||
.cell(Cell::new(id).bold_if(unseen).red())
|
.cell(Cell::new(hash).bold_if(unseen).red())
|
||||||
.cell(Cell::new(flags).bold_if(unseen).white())
|
.cell(Cell::new(flags).bold_if(unseen).white())
|
||||||
.cell(Cell::new(subject).shrinkable().bold_if(unseen).green())
|
.cell(Cell::new(subject).shrinkable().bold_if(unseen).green())
|
||||||
.cell(Cell::new(sender).bold_if(unseen).blue())
|
.cell(Cell::new(sender).bold_if(unseen).blue())
|
||||||
|
@ -117,7 +120,8 @@ impl<'a> TryFrom<RawNotmuchEnvelope> for NotmuchEnvelope {
|
||||||
fn try_from(raw_envelope: RawNotmuchEnvelope) -> Result<Self, Self::Error> {
|
fn try_from(raw_envelope: RawNotmuchEnvelope) -> Result<Self, Self::Error> {
|
||||||
info!("begin: try building envelope from notmuch parsed mail");
|
info!("begin: try building envelope from notmuch parsed mail");
|
||||||
|
|
||||||
let id = raw_envelope.id().trim().to_string();
|
let id = raw_envelope.id().to_string();
|
||||||
|
let hash = format!("{:x}", md5::compute(&id));
|
||||||
let subject = raw_envelope
|
let subject = raw_envelope
|
||||||
.header("subject")
|
.header("subject")
|
||||||
.context("cannot get header \"Subject\" from notmuch message")?
|
.context("cannot get header \"Subject\" from notmuch message")?
|
||||||
|
@ -159,6 +163,7 @@ impl<'a> TryFrom<RawNotmuchEnvelope> for NotmuchEnvelope {
|
||||||
|
|
||||||
let envelope = Self {
|
let envelope = Self {
|
||||||
id,
|
id,
|
||||||
|
hash,
|
||||||
flags: raw_envelope.tags().collect(),
|
flags: raw_envelope.tags().collect(),
|
||||||
subject,
|
subject,
|
||||||
sender,
|
sender,
|
||||||
|
|
Loading…
Reference in a new issue