melib/notmuch: avoid parsing entire email in Envelope creation

jmap-eventsource
Manos Pitsidianakis 2021-01-05 01:13:13 +02:00
parent 806254436b
commit db69349251
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
2 changed files with 98 additions and 53 deletions

View File

@ -22,7 +22,7 @@
use crate::backends::*; use crate::backends::*;
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
use crate::email::{Envelope, EnvelopeHash, Flag}; use crate::email::{Envelope, EnvelopeHash, Flag};
use crate::error::{MeliError, Result, ResultIntoMeliError}; use crate::error::{MeliError, Result};
use crate::shellexpand::ShellExpandTrait; use crate::shellexpand::ShellExpandTrait;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::collections::{ use std::collections::{
@ -130,31 +130,25 @@ impl DbConnection {
} }
} else { } else {
let message_id = message.msg_id_cstr().to_string_lossy().to_string(); let message_id = message.msg_id_cstr().to_string_lossy().to_string();
match message.into_envelope(index.clone(), tag_index.clone()) { let env = message.into_envelope(&index, &tag_index);
Ok(env) => { for (&mailbox_hash, m) in mailboxes_lck.iter() {
for (&mailbox_hash, m) in mailboxes_lck.iter() { let query_str = format!("{} id:{}", m.query_str.as_str(), &message_id);
let query_str = format!("{} id:{}", m.query_str.as_str(), &message_id); let query: Query = Query::new(self, &query_str)?;
let query: Query = Query::new(self, &query_str)?; if query.count().unwrap_or(0) > 0 {
if query.count().unwrap_or(0) > 0 { let mut total_lck = m.total.lock().unwrap();
let mut total_lck = m.total.lock().unwrap(); let mut unseen_lck = m.unseen.lock().unwrap();
let mut unseen_lck = m.unseen.lock().unwrap(); *total_lck += 1;
*total_lck += 1; if !env.is_seen() {
if !env.is_seen() { *unseen_lck += 1;
*unseen_lck += 1;
}
(event_consumer)(
account_hash,
BackendEvent::Refresh(RefreshEvent {
account_hash,
mailbox_hash,
kind: Create(Box::new(env.clone())),
}),
);
}
} }
} (event_consumer)(
Err(err) => { account_hash,
debug!("could not parse message {:?}", err); BackendEvent::Refresh(RefreshEvent {
account_hash,
mailbox_hash,
kind: Create(Box::new(env.clone())),
}),
);
} }
} }
} }
@ -481,21 +475,15 @@ impl MailBackend for NotmuchDb {
} else { } else {
continue; continue;
}; };
match message.into_envelope(self.index.clone(), self.tag_index.clone()) { let env = message.into_envelope(&self.index, &self.tag_index);
Ok(env) => { mailbox_index_lck
mailbox_index_lck .entry(env.hash())
.entry(env.hash()) .or_default()
.or_default() .push(self.mailbox_hash);
.push(self.mailbox_hash); if !env.is_seen() {
if !env.is_seen() { unseen_count += 1;
unseen_count += 1;
}
ret.push(env);
}
Err(err) => {
debug!("could not parse message {:?}", err);
}
} }
ret.push(env);
} else { } else {
done = true; done = true;
break; break;

View File

@ -65,6 +65,16 @@ impl<'m> Message<'m> {
} }
} }
pub fn header(&self, header: &CStr) -> Option<&[u8]> {
let header_val =
unsafe { call!(self.lib, notmuch_message_get_header)(self.message, header.as_ptr()) };
if header_val.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(header_val).to_bytes() })
}
}
pub fn msg_id(&self) -> &[u8] { pub fn msg_id(&self) -> &[u8] {
let c_str = self.msg_id_cstr(); let c_str = self.msg_id_cstr();
c_str.to_bytes() c_str.to_bytes()
@ -81,19 +91,11 @@ impl<'m> Message<'m> {
pub fn into_envelope( pub fn into_envelope(
self, self,
index: Arc<RwLock<HashMap<EnvelopeHash, CString>>>, index: &RwLock<HashMap<EnvelopeHash, CString>>,
tag_index: Arc<RwLock<BTreeMap<u64, String>>>, tag_index: &RwLock<BTreeMap<u64, String>>,
) -> Result<Envelope> { ) -> Envelope {
let mut contents = Vec::new();
let path = self.get_filename().to_os_string();
let mut f = std::fs::File::open(&path)?;
f.read_to_end(&mut contents)?;
let env_hash = self.env_hash(); let env_hash = self.env_hash();
let mut env = Envelope::from_bytes(&contents, None).chain_err_summary(|| { let mut env = Envelope::new(env_hash);
index.write().unwrap().remove(&env_hash);
format!("could not parse path {:?}", path)
})?;
env.set_hash(env_hash);
index index
.write() .write()
.unwrap() .unwrap()
@ -109,8 +111,63 @@ impl<'m> Message<'m> {
} }
env.labels_mut().push(num); env.labels_mut().push(num);
} }
env.set_flags(flags); unsafe {
Ok(env) use crate::email::parser::address::rfc2822address_list;
env.set_message_id(self.msg_id())
.set_date(
self.header(CStr::from_bytes_with_nul_unchecked(b"Date\0"))
.unwrap_or_default(),
)
.set_from(
rfc2822address_list(
self.header(CStr::from_bytes_with_nul_unchecked(b"From\0"))
.unwrap_or_default(),
)
.map(|(_, v)| v)
.unwrap_or_default(),
)
.set_to(
rfc2822address_list(
self.header(CStr::from_bytes_with_nul_unchecked(b"To\0"))
.unwrap_or_default(),
)
.map(|(_, v)| v)
.unwrap_or_default(),
)
.set_cc(
rfc2822address_list(
self.header(CStr::from_bytes_with_nul_unchecked(b"Cc\0"))
.unwrap_or_default(),
)
.map(|(_, v)| v)
.unwrap_or_default(),
)
.set_bcc(
rfc2822address_list(
self.header(CStr::from_bytes_with_nul_unchecked(b"Bcc\0"))
.unwrap_or_default(),
)
.map(|(_, v)| v)
.unwrap_or_default()
.to_vec(),
)
.set_subject(
self.header(CStr::from_bytes_with_nul_unchecked(b"Subject\0"))
.unwrap_or_default()
.to_vec(),
)
.set_references(
self.header(CStr::from_bytes_with_nul_unchecked(b"References\0"))
.unwrap_or_default(),
)
.set_in_reply_to(
self.header(CStr::from_bytes_with_nul_unchecked(b"In-Reply-To\0"))
.unwrap_or_default(),
)
.set_datetime(self.date())
.set_flags(flags);
}
env
} }
pub fn replies_iter(&self) -> Option<MessageIterator> { pub fn replies_iter(&self) -> Option<MessageIterator> {