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::conf::AccountSettings;
use crate::email::{Envelope, EnvelopeHash, Flag};
use crate::error::{MeliError, Result, ResultIntoMeliError};
use crate::error::{MeliError, Result};
use crate::shellexpand::ShellExpandTrait;
use smallvec::SmallVec;
use std::collections::{
@ -130,31 +130,25 @@ impl DbConnection {
}
} else {
let message_id = message.msg_id_cstr().to_string_lossy().to_string();
match message.into_envelope(index.clone(), tag_index.clone()) {
Ok(env) => {
for (&mailbox_hash, m) in mailboxes_lck.iter() {
let query_str = format!("{} id:{}", m.query_str.as_str(), &message_id);
let query: Query = Query::new(self, &query_str)?;
if query.count().unwrap_or(0) > 0 {
let mut total_lck = m.total.lock().unwrap();
let mut unseen_lck = m.unseen.lock().unwrap();
*total_lck += 1;
if !env.is_seen() {
*unseen_lck += 1;
}
(event_consumer)(
account_hash,
BackendEvent::Refresh(RefreshEvent {
account_hash,
mailbox_hash,
kind: Create(Box::new(env.clone())),
}),
);
}
let env = message.into_envelope(&index, &tag_index);
for (&mailbox_hash, m) in mailboxes_lck.iter() {
let query_str = format!("{} id:{}", m.query_str.as_str(), &message_id);
let query: Query = Query::new(self, &query_str)?;
if query.count().unwrap_or(0) > 0 {
let mut total_lck = m.total.lock().unwrap();
let mut unseen_lck = m.unseen.lock().unwrap();
*total_lck += 1;
if !env.is_seen() {
*unseen_lck += 1;
}
}
Err(err) => {
debug!("could not parse message {:?}", err);
(event_consumer)(
account_hash,
BackendEvent::Refresh(RefreshEvent {
account_hash,
mailbox_hash,
kind: Create(Box::new(env.clone())),
}),
);
}
}
}
@ -481,21 +475,15 @@ impl MailBackend for NotmuchDb {
} else {
continue;
};
match message.into_envelope(self.index.clone(), self.tag_index.clone()) {
Ok(env) => {
mailbox_index_lck
.entry(env.hash())
.or_default()
.push(self.mailbox_hash);
if !env.is_seen() {
unseen_count += 1;
}
ret.push(env);
}
Err(err) => {
debug!("could not parse message {:?}", err);
}
let env = message.into_envelope(&self.index, &self.tag_index);
mailbox_index_lck
.entry(env.hash())
.or_default()
.push(self.mailbox_hash);
if !env.is_seen() {
unseen_count += 1;
}
ret.push(env);
} else {
done = true;
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] {
let c_str = self.msg_id_cstr();
c_str.to_bytes()
@ -81,19 +91,11 @@ impl<'m> Message<'m> {
pub fn into_envelope(
self,
index: Arc<RwLock<HashMap<EnvelopeHash, CString>>>,
tag_index: Arc<RwLock<BTreeMap<u64, String>>>,
) -> Result<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)?;
index: &RwLock<HashMap<EnvelopeHash, CString>>,
tag_index: &RwLock<BTreeMap<u64, String>>,
) -> Envelope {
let env_hash = self.env_hash();
let mut env = Envelope::from_bytes(&contents, None).chain_err_summary(|| {
index.write().unwrap().remove(&env_hash);
format!("could not parse path {:?}", path)
})?;
env.set_hash(env_hash);
let mut env = Envelope::new(env_hash);
index
.write()
.unwrap()
@ -109,8 +111,63 @@ impl<'m> Message<'m> {
}
env.labels_mut().push(num);
}
env.set_flags(flags);
Ok(env)
unsafe {
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> {