mirror of
https://github.com/soywod/himalaya.git
synced 2025-04-22 17:23:27 +00:00
add id mapper to notmuch backend
This commit is contained in:
parent
ad1f97faed
commit
6606bd9f16
2 changed files with 92 additions and 58 deletions
src/backends/notmuch
|
@ -3,7 +3,7 @@ use std::{convert::TryInto, fs};
|
|||
use anyhow::{anyhow, Context, Result};
|
||||
|
||||
use crate::{
|
||||
backends::{Backend, NotmuchEnvelopes, NotmuchMbox, NotmuchMboxes},
|
||||
backends::{Backend, IdMapper, NotmuchEnvelopes, NotmuchMbox, NotmuchMboxes},
|
||||
config::{AccountConfig, NotmuchBackendConfig},
|
||||
mbox::Mboxes,
|
||||
msg::{Envelopes, Msg},
|
||||
|
@ -11,6 +11,7 @@ use crate::{
|
|||
|
||||
pub struct NotmuchBackend<'a> {
|
||||
account_config: &'a AccountConfig,
|
||||
notmuch_config: &'a NotmuchBackendConfig,
|
||||
db: notmuch::Database,
|
||||
}
|
||||
|
||||
|
@ -21,6 +22,7 @@ impl<'a> NotmuchBackend<'a> {
|
|||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
account_config,
|
||||
notmuch_config,
|
||||
db: notmuch::Database::open(
|
||||
notmuch_config.notmuch_database_dir.clone(),
|
||||
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> {
|
||||
|
@ -55,81 +115,44 @@ impl<'a> Backend<'a> for NotmuchBackend<'a> {
|
|||
|
||||
fn get_envelopes(
|
||||
&mut self,
|
||||
mbox: &str,
|
||||
virt_mbox: &str,
|
||||
page_size: usize,
|
||||
page: usize,
|
||||
) -> Result<Box<dyn Envelopes>> {
|
||||
let query = self
|
||||
.account_config
|
||||
.mailboxes
|
||||
.get(mbox)
|
||||
.get(virt_mbox)
|
||||
.map(|s| s.as_str())
|
||||
.unwrap_or("all");
|
||||
let query_builder = self
|
||||
.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))
|
||||
self._search_envelopes(query, virt_mbox, page_size, page)
|
||||
}
|
||||
|
||||
fn find_envelopes(
|
||||
fn search_envelopes(
|
||||
&mut self,
|
||||
_mbox: &str,
|
||||
virt_mbox: &str,
|
||||
query: &str,
|
||||
_sort: &str,
|
||||
page_size: usize,
|
||||
page: usize,
|
||||
) -> Result<Box<dyn Envelopes>> {
|
||||
let query_builder = self
|
||||
.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))
|
||||
self._search_envelopes(query, virt_mbox, page_size, page)
|
||||
}
|
||||
|
||||
fn add_msg(&mut self, _mbox: &str, _msg: &[u8], _flags: &str) -> Result<Box<dyn ToString>> {
|
||||
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
|
||||
.db
|
||||
.find_message(id)
|
||||
.find_message(&id)
|
||||
.context(format!("cannot find notmuch message {:?}", id))?
|
||||
.ok_or_else(|| anyhow!("cannot find notmuch message {:?}", id))?
|
||||
.filename()
|
||||
|
@ -148,10 +171,16 @@ impl<'a> Backend<'a> for NotmuchBackend<'a> {
|
|||
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
|
||||
.db
|
||||
.find_message(id)
|
||||
.find_message(&id)
|
||||
.context(format!("cannot find notmuch message {:?}", id))?
|
||||
.ok_or_else(|| anyhow!("cannot find notmuch message {:?}", id))?
|
||||
.filename()
|
||||
|
|
|
@ -51,6 +51,9 @@ pub struct NotmuchEnvelope {
|
|||
/// Represents the id of the message.
|
||||
pub id: String,
|
||||
|
||||
/// Represents the MD5 hash of the message id.
|
||||
pub hash: String,
|
||||
|
||||
/// Represents the tags of the message.
|
||||
pub flags: Vec<String>,
|
||||
|
||||
|
@ -67,7 +70,7 @@ pub struct NotmuchEnvelope {
|
|||
impl Table for NotmuchEnvelope {
|
||||
fn head() -> Row {
|
||||
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("SUBJECT").shrinkable().bold().underline().white())
|
||||
.cell(Cell::new("SENDER").bold().underline().white())
|
||||
|
@ -75,14 +78,14 @@ impl Table for NotmuchEnvelope {
|
|||
}
|
||||
|
||||
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 flags = String::new();
|
||||
let subject = &self.subject;
|
||||
let sender = &self.sender;
|
||||
let date = &self.date;
|
||||
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(subject).shrinkable().bold_if(unseen).green())
|
||||
.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> {
|
||||
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
|
||||
.header("subject")
|
||||
.context("cannot get header \"Subject\" from notmuch message")?
|
||||
|
@ -159,6 +163,7 @@ impl<'a> TryFrom<RawNotmuchEnvelope> for NotmuchEnvelope {
|
|||
|
||||
let envelope = Self {
|
||||
id,
|
||||
hash,
|
||||
flags: raw_envelope.tags().collect(),
|
||||
subject,
|
||||
sender,
|
||||
|
|
Loading…
Add table
Reference in a new issue