Load libnotmuch dynamically

memfd
Manos Pitsidianakis 2020-02-26 14:18:00 +02:00
parent ac71d627f1
commit 303c530488
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
7 changed files with 1850 additions and 2513 deletions

11
Cargo.lock generated
View File

@ -607,6 +607,15 @@ dependencies = [
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "libloading"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "libsqlite3-sys" name = "libsqlite3-sys"
version = "0.16.0" version = "0.16.0"
@ -712,6 +721,7 @@ dependencies = [
"encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1897,6 +1907,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
"checksum libdbus-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc12a3bc971424edbbf7edaf6e5740483444db63aa8e23d3751ff12a30f306f0" "checksum libdbus-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc12a3bc971424edbbf7edaf6e5740483444db63aa8e23d3751ff12a30f306f0"
"checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753"
"checksum libsqlite3-sys 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5b95e89c330291768dc840238db7f9e204fd208511ab6319b56193a7f2ae25" "checksum libsqlite3-sys 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5b95e89c330291768dc840238db7f9e204fd208511ab6319b56193a7f2ae25"
"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
"checksum linkify 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ce9439c6f4a1092dc1861272bef01034891da39f13aa1cdcf40ca3e4081de5f" "checksum linkify 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ce9439c6f4a1092dc1861272bef01034891da39f13aa1cdcf40ca3e4081de5f"

View File

@ -55,7 +55,7 @@ debug = false
members = ["melib", "testing", ] members = ["melib", "testing", ]
[features] [features]
default = ["sqlite3"] default = ["sqlite3", "notmuch"]
notmuch = ["melib/notmuch_backend", ] notmuch = ["melib/notmuch_backend", ]
jmap = ["melib/jmap_backend",] jmap = ["melib/jmap_backend",]
sqlite3 = ["rusqlite"] sqlite3 = ["rusqlite"]

View File

@ -42,6 +42,8 @@ serde_json = { version = "1.0", optional = true, features = ["raw_value",] }
smallvec = { version = "1.1.0", features = ["serde", ] } smallvec = { version = "1.1.0", features = ["serde", ] }
nix = "0.16.1" nix = "0.16.1"
libloading = "0.5.2"
[features] [features]
default = ["unicode_algorithms", "imap_backend", "maildir_backend", "mbox_backend", "vcard"] default = ["unicode_algorithms", "imap_backend", "maildir_backend", "mbox_backend", "vcard"]

View File

@ -23,10 +23,6 @@
include!("src/text_processing/types.rs"); include!("src/text_processing/types.rs");
fn main() -> Result<(), std::io::Error> { fn main() -> Result<(), std::io::Error> {
#[cfg(feature = "notmuch_backend")]
{
println!("cargo:rustc-link-lib=notmuch");
}
#[cfg(feature = "unicode_algorithms")] #[cfg(feature = "unicode_algorithms")]
{ {
use std::fs::File; use std::fs::File;

View File

@ -99,6 +99,12 @@ impl Default for Backends {
} }
} }
#[cfg(feature = "notmuch_backend")]
pub const NOTMUCH_ERROR_MSG: &'static str =
"libnotmuch5 was not found in your system. Make sure it is installed and in the library paths.\n";
#[cfg(not(feature = "notmuch_backend"))]
pub const NOTMUCH_ERROR_MSG: &'static str = "this version of meli is not compiled with notmuch support. Use an appropriate version and make sure libnotmuch5 is installed and in the library paths.\n";
impl Backends { impl Backends {
pub fn new() -> Self { pub fn new() -> Self {
let mut b = Backends { let mut b = Backends {
@ -136,13 +142,15 @@ impl Backends {
} }
#[cfg(feature = "notmuch_backend")] #[cfg(feature = "notmuch_backend")]
{ {
b.register( if libloading::Library::new("libnotmuch.so.5").is_ok() {
"notmuch".to_string(), b.register(
Backend { "notmuch".to_string(),
create_fn: Box::new(|| Box::new(|f, i| NotmuchDb::new(f, i))), Backend {
validate_conf_fn: Box::new(NotmuchDb::validate_config), create_fn: Box::new(|| Box::new(|f, i| NotmuchDb::new(f, i))),
}, validate_conf_fn: Box::new(NotmuchDb::validate_config),
); },
);
}
} }
#[cfg(feature = "jmap_backend")] #[cfg(feature = "jmap_backend")]
{ {
@ -159,6 +167,9 @@ impl Backends {
pub fn get(&self, key: &str) -> BackendCreator { pub fn get(&self, key: &str) -> BackendCreator {
if !self.map.contains_key(key) { if !self.map.contains_key(key) {
if key == "notmuch" {
eprint!("{}", NOTMUCH_ERROR_MSG);
}
panic!("{} is not a valid mail backend", key); panic!("{} is not a valid mail backend", key);
} }
(self.map[key].create_fn)() (self.map[key].create_fn)()
@ -175,7 +186,17 @@ impl Backends {
(self (self
.map .map
.get(key) .get(key)
.ok_or_else(|| MeliError::new(format!("{} is not a valid mail backend", key)))? .ok_or_else(|| {
MeliError::new(format!(
"{}{} is not a valid mail backend",
if key == "notmuch" {
NOTMUCH_ERROR_MSG
} else {
""
},
key
))
})?
.validate_conf_fn)(s) .validate_conf_fn)(s)
} }
} }

View File

@ -54,6 +54,7 @@ unsafe impl Sync for DbWrapper {}
#[derive(Debug)] #[derive(Debug)]
pub struct NotmuchDb { pub struct NotmuchDb {
database: DbWrapper, database: DbWrapper,
lib: Arc<libloading::Library>,
mailboxes: Arc<RwLock<FnvHashMap<MailboxHash, NotmuchMailbox>>>, mailboxes: Arc<RwLock<FnvHashMap<MailboxHash, NotmuchMailbox>>>,
index: Arc<RwLock<FnvHashMap<EnvelopeHash, &'static CStr>>>, index: Arc<RwLock<FnvHashMap<EnvelopeHash, &'static CStr>>>,
tag_index: Arc<RwLock<BTreeMap<u64, String>>>, tag_index: Arc<RwLock<BTreeMap<u64, String>>>,
@ -64,19 +65,26 @@ pub struct NotmuchDb {
unsafe impl Send for NotmuchDb {} unsafe impl Send for NotmuchDb {}
unsafe impl Sync for NotmuchDb {} unsafe impl Sync for NotmuchDb {}
macro_rules! call {
($lib:expr, $func:ty) => {{
let func: libloading::Symbol<$func> = $lib.get(stringify!($func).as_bytes()).unwrap();
func
}};
}
impl Drop for NotmuchDb { impl Drop for NotmuchDb {
fn drop(&mut self) { fn drop(&mut self) {
for f in self.mailboxes.write().unwrap().values_mut() { for f in self.mailboxes.write().unwrap().values_mut() {
if let Some(query) = f.query.take() { if let Some(query) = f.query.take() {
unsafe { unsafe {
notmuch_query_destroy(query); call!(self.lib, notmuch_query_destroy)(query);
} }
} }
} }
let inner = self.database.inner.write().unwrap(); let inner = self.database.inner.write().unwrap();
unsafe { unsafe {
notmuch_database_close(*inner); call!(self.lib, notmuch_database_close)(*inner);
notmuch_database_destroy(*inner); call!(self.lib, notmuch_database_destroy)(*inner);
} }
} }
} }
@ -158,6 +166,7 @@ impl NotmuchDb {
s: &AccountSettings, s: &AccountSettings,
_is_subscribed: Box<dyn Fn(&str) -> bool>, _is_subscribed: Box<dyn Fn(&str) -> bool>,
) -> Result<Box<dyn MailBackend>> { ) -> Result<Box<dyn MailBackend>> {
let lib = Arc::new(libloading::Library::new("libnotmuch.so.5")?);
let mut database: *mut notmuch_database_t = std::ptr::null_mut(); let mut database: *mut notmuch_database_t = std::ptr::null_mut();
let path = Path::new(s.root_mailbox.as_str()).expand().to_path_buf(); let path = Path::new(s.root_mailbox.as_str()).expand().to_path_buf();
if !path.exists() { if !path.exists() {
@ -171,7 +180,7 @@ impl NotmuchDb {
let path_c = std::ffi::CString::new(path.to_str().unwrap()).unwrap(); let path_c = std::ffi::CString::new(path.to_str().unwrap()).unwrap();
let path_ptr = path_c.as_ptr(); let path_ptr = path_c.as_ptr();
let status = unsafe { let status = unsafe {
bindings::notmuch_database_open( call!(lib, notmuch_database_open)(
path_ptr, path_ptr,
notmuch_database_mode_t_NOTMUCH_DATABASE_MODE_READ_WRITE, notmuch_database_mode_t_NOTMUCH_DATABASE_MODE_READ_WRITE,
&mut database as *mut _, &mut database as *mut _,
@ -217,6 +226,7 @@ impl NotmuchDb {
} }
} }
Ok(Box::new(NotmuchDb { Ok(Box::new(NotmuchDb {
lib,
database: DbWrapper { database: DbWrapper {
inner: Arc::new(RwLock::new(database)), inner: Arc::new(RwLock::new(database)),
database_ph: std::marker::PhantomData, database_ph: std::marker::PhantomData,
@ -254,12 +264,14 @@ impl NotmuchDb {
let database_lck = self.database.inner.read().unwrap(); let database_lck = self.database.inner.read().unwrap();
let query_str = std::ffi::CString::new(query_s).unwrap(); let query_str = std::ffi::CString::new(query_s).unwrap();
let query: *mut notmuch_query_t = let query: *mut notmuch_query_t =
unsafe { notmuch_query_create(*database_lck, query_str.as_ptr()) }; unsafe { call!(self.lib, notmuch_query_create)(*database_lck, query_str.as_ptr()) };
if query.is_null() { if query.is_null() {
return Err(MeliError::new("Could not create query. Out of memory?")); return Err(MeliError::new("Could not create query. Out of memory?"));
} }
let mut messages: *mut notmuch_messages_t = std::ptr::null_mut(); let mut messages: *mut notmuch_messages_t = std::ptr::null_mut();
let status = unsafe { notmuch_query_search_messages(query, &mut messages as *mut _) }; let status = unsafe {
call!(self.lib, notmuch_query_search_messages)(query, &mut messages as *mut _)
};
if status != 0 { if status != 0 {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"Search for {} returned {}", "Search for {} returned {}",
@ -267,10 +279,13 @@ impl NotmuchDb {
))); )));
} }
assert!(!messages.is_null()); assert!(!messages.is_null());
let iter = MessageIterator { messages }; let iter = MessageIterator {
messages,
lib: self.lib.clone(),
};
let mut ret = SmallVec::new(); let mut ret = SmallVec::new();
for message in iter { for message in iter {
let fs_path = unsafe { notmuch_message_get_filename(message) }; let fs_path = unsafe { call!(self.lib, notmuch_message_get_filename)(message) };
let c_str = unsafe { CStr::from_ptr(fs_path) }; let c_str = unsafe { CStr::from_ptr(fs_path) };
let env_hash = { let env_hash = {
let mut hasher = DefaultHasher::default(); let mut hasher = DefaultHasher::default();
@ -295,6 +310,7 @@ impl MailBackend for NotmuchDb {
let index = self.index.clone(); let index = self.index.clone();
let tag_index = self.tag_index.clone(); let tag_index = self.tag_index.clone();
let mailboxes = self.mailboxes.clone(); let mailboxes = self.mailboxes.clone();
let lib = self.lib.clone();
let handle = { let handle = {
let tx = w.tx(); let tx = w.tx();
let closure = move |_work_context| { let closure = move |_work_context| {
@ -304,7 +320,7 @@ impl MailBackend for NotmuchDb {
let mailbox = mailboxes_lck.get_mut(&mailbox_hash).unwrap(); let mailbox = mailboxes_lck.get_mut(&mailbox_hash).unwrap();
let query_str = std::ffi::CString::new(mailbox.query_str.as_str()).unwrap(); let query_str = std::ffi::CString::new(mailbox.query_str.as_str()).unwrap();
let query: *mut notmuch_query_t = let query: *mut notmuch_query_t =
unsafe { notmuch_query_create(*database_lck, query_str.as_ptr()) }; unsafe { call!(lib, notmuch_query_create)(*database_lck, query_str.as_ptr()) };
if query.is_null() { if query.is_null() {
tx.send(AsyncStatus::Payload(Err(MeliError::new( tx.send(AsyncStatus::Payload(Err(MeliError::new(
"Could not create query. Out of memory?", "Could not create query. Out of memory?",
@ -314,8 +330,9 @@ impl MailBackend for NotmuchDb {
return; return;
} }
let mut messages: *mut notmuch_messages_t = std::ptr::null_mut(); let mut messages: *mut notmuch_messages_t = std::ptr::null_mut();
let status = let status = unsafe {
unsafe { notmuch_query_search_messages(query, &mut messages as *mut _) }; call!(lib, notmuch_query_search_messages)(query, &mut messages as *mut _)
};
if status != 0 { if status != 0 {
tx.send(AsyncStatus::Payload(Err(MeliError::new(format!( tx.send(AsyncStatus::Payload(Err(MeliError::new(format!(
"Search for {} returned {}", "Search for {} returned {}",
@ -327,10 +344,13 @@ impl MailBackend for NotmuchDb {
return; return;
} }
assert!(!messages.is_null()); assert!(!messages.is_null());
let iter = MessageIterator { messages }; let iter = MessageIterator {
messages,
lib: lib.clone(),
};
for message in iter { for message in iter {
let mut response = String::new(); let mut response = String::new();
let fs_path = unsafe { notmuch_message_get_filename(message) }; let fs_path = unsafe { call!(lib, notmuch_message_get_filename)(message) };
let mut f = match std::fs::File::open(unsafe { let mut f = match std::fs::File::open(unsafe {
CStr::from_ptr(fs_path) CStr::from_ptr(fs_path)
.to_string_lossy() .to_string_lossy()
@ -357,6 +377,7 @@ impl MailBackend for NotmuchDb {
index.write().unwrap().insert(env_hash, c_str); index.write().unwrap().insert(env_hash, c_str);
let op = Box::new(NotmuchOp { let op = Box::new(NotmuchOp {
database: database.clone(), database: database.clone(),
lib: lib.clone(),
hash: env_hash, hash: env_hash,
index: index.clone(), index: index.clone(),
bytes: Some(response), bytes: Some(response),
@ -365,7 +386,8 @@ impl MailBackend for NotmuchDb {
if let Some(mut env) = Envelope::from_token(op, env_hash) { if let Some(mut env) = Envelope::from_token(op, env_hash) {
let mut tag_lock = tag_index.write().unwrap(); let mut tag_lock = tag_index.write().unwrap();
for tag in (TagIterator { for tag in (TagIterator {
tags: unsafe { notmuch_message_get_tags(message) }, tags: unsafe { call!(lib, notmuch_message_get_tags)(message) },
lib: lib.clone(),
}) { }) {
let tag = tag.to_string_lossy().into_owned(); let tag = tag.to_string_lossy().into_owned();
@ -417,6 +439,7 @@ impl MailBackend for NotmuchDb {
fn operation(&self, hash: EnvelopeHash) -> Box<dyn BackendOp> { fn operation(&self, hash: EnvelopeHash) -> Box<dyn BackendOp> {
Box::new(NotmuchOp { Box::new(NotmuchOp {
database: self.database.clone(), database: self.database.clone(),
lib: self.lib.clone(),
hash, hash,
index: self.index.clone(), index: self.index.clone(),
bytes: None, bytes: None,
@ -462,6 +485,7 @@ struct NotmuchOp {
tag_index: Arc<RwLock<BTreeMap<u64, String>>>, tag_index: Arc<RwLock<BTreeMap<u64, String>>>,
database: DbWrapper, database: DbWrapper,
bytes: Option<String>, bytes: Option<String>,
lib: Arc<libloading::Library>,
} }
impl BackendOp for NotmuchOp { impl BackendOp for NotmuchOp {
@ -507,7 +531,7 @@ impl BackendOp for NotmuchOp {
let mut message: *mut notmuch_message_t = std::ptr::null_mut(); let mut message: *mut notmuch_message_t = std::ptr::null_mut();
let mut index_lck = self.index.write().unwrap(); let mut index_lck = self.index.write().unwrap();
unsafe { unsafe {
notmuch_database_find_message_by_filename( call!(self.lib, notmuch_database_find_message_by_filename)(
*self.database.inner.read().unwrap(), *self.database.inner.read().unwrap(),
index_lck[&self.hash].as_ptr(), index_lck[&self.hash].as_ptr(),
&mut message as *mut _, &mut message as *mut _,
@ -521,7 +545,8 @@ impl BackendOp for NotmuchOp {
} }
let tags = (TagIterator { let tags = (TagIterator {
tags: unsafe { notmuch_message_get_tags(message) }, tags: unsafe { call!(self.lib, notmuch_message_get_tags)(message) },
lib: self.lib.clone(),
}) })
.collect::<Vec<&CStr>>(); .collect::<Vec<&CStr>>();
debug!(&tags); debug!(&tags);
@ -537,7 +562,7 @@ impl BackendOp for NotmuchOp {
if tags.contains(&cstr!($l)) { if tags.contains(&cstr!($l)) {
return Ok(()); return Ok(());
} }
if notmuch_message_add_tag(message, cstr!($l).as_ptr()) if call!(self.lib, notmuch_message_add_tag)(message, cstr!($l).as_ptr())
!= _notmuch_status_NOTMUCH_STATUS_SUCCESS != _notmuch_status_NOTMUCH_STATUS_SUCCESS
{ {
return Err(MeliError::new("Could not set tag.")); return Err(MeliError::new("Could not set tag."));
@ -551,7 +576,7 @@ impl BackendOp for NotmuchOp {
if !tags.contains(&cstr!($l)) { if !tags.contains(&cstr!($l)) {
return Ok(()); return Ok(());
} }
if notmuch_message_remove_tag(message, cstr!($l).as_ptr()) if call!(self.lib, notmuch_message_remove_tag)(message, cstr!($l).as_ptr())
!= _notmuch_status_NOTMUCH_STATUS_SUCCESS != _notmuch_status_NOTMUCH_STATUS_SUCCESS
{ {
return Err(MeliError::new("Could not set tag.")); return Err(MeliError::new("Could not set tag."));
@ -577,13 +602,13 @@ impl BackendOp for NotmuchOp {
} }
/* Update message filesystem path. */ /* Update message filesystem path. */
if unsafe { notmuch_message_tags_to_maildir_flags(message) } if unsafe { call!(self.lib, notmuch_message_tags_to_maildir_flags)(message) }
!= _notmuch_status_NOTMUCH_STATUS_SUCCESS != _notmuch_status_NOTMUCH_STATUS_SUCCESS
{ {
return Err(MeliError::new("Could not set tag.")); return Err(MeliError::new("Could not set tag."));
} }
let fs_path = unsafe { notmuch_message_get_filename(message) }; let fs_path = unsafe { call!(self.lib, notmuch_message_get_filename)(message) };
let c_str = unsafe { CStr::from_ptr(fs_path) }; let c_str = unsafe { CStr::from_ptr(fs_path) };
if let Some(p) = index_lck.get_mut(&self.hash) { if let Some(p) = index_lck.get_mut(&self.hash) {
*p = c_str; *p = c_str;
@ -602,7 +627,7 @@ impl BackendOp for NotmuchOp {
let mut message: *mut notmuch_message_t = std::ptr::null_mut(); let mut message: *mut notmuch_message_t = std::ptr::null_mut();
let index_lck = self.index.read().unwrap(); let index_lck = self.index.read().unwrap();
unsafe { unsafe {
notmuch_database_find_message_by_filename( call!(self.lib, notmuch_database_find_message_by_filename)(
*self.database.inner.read().unwrap(), *self.database.inner.read().unwrap(),
index_lck[&self.hash].as_ptr(), index_lck[&self.hash].as_ptr(),
&mut message as *mut _, &mut message as *mut _,
@ -616,7 +641,10 @@ impl BackendOp for NotmuchOp {
} }
if value { if value {
if unsafe { if unsafe {
notmuch_message_add_tag(message, CString::new(tag.as_str()).unwrap().as_ptr()) call!(self.lib, notmuch_message_add_tag)(
message,
CString::new(tag.as_str()).unwrap().as_ptr(),
)
} != _notmuch_status_NOTMUCH_STATUS_SUCCESS } != _notmuch_status_NOTMUCH_STATUS_SUCCESS
{ {
return Err(MeliError::new("Could not set tag.")); return Err(MeliError::new("Could not set tag."));
@ -624,7 +652,10 @@ impl BackendOp for NotmuchOp {
debug!("added tag {}", &tag); debug!("added tag {}", &tag);
} else { } else {
if unsafe { if unsafe {
notmuch_message_remove_tag(message, CString::new(tag.as_str()).unwrap().as_ptr()) call!(self.lib, notmuch_message_remove_tag)(
message,
CString::new(tag.as_str()).unwrap().as_ptr(),
)
} != _notmuch_status_NOTMUCH_STATUS_SUCCESS } != _notmuch_status_NOTMUCH_STATUS_SUCCESS
{ {
return Err(MeliError::new("Could not set tag.")); return Err(MeliError::new("Could not set tag."));
@ -652,6 +683,7 @@ impl BackendOp for NotmuchOp {
} }
pub struct MessageIterator { pub struct MessageIterator {
lib: Arc<libloading::Library>,
messages: *mut notmuch_messages_t, messages: *mut notmuch_messages_t,
} }
@ -660,10 +692,10 @@ impl Iterator for MessageIterator {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.messages.is_null() { if self.messages.is_null() {
None None
} else if unsafe { notmuch_messages_valid(self.messages) } == 1 { } else if unsafe { call!(self.lib, notmuch_messages_valid)(self.messages) } == 1 {
let ret = Some(unsafe { notmuch_messages_get(self.messages) }); let ret = Some(unsafe { call!(self.lib, notmuch_messages_get)(self.messages) });
unsafe { unsafe {
notmuch_messages_move_to_next(self.messages); call!(self.lib, notmuch_messages_move_to_next)(self.messages);
} }
ret ret
} else { } else {
@ -674,6 +706,7 @@ impl Iterator for MessageIterator {
} }
pub struct TagIterator { pub struct TagIterator {
lib: Arc<libloading::Library>,
tags: *mut notmuch_tags_t, tags: *mut notmuch_tags_t,
} }
@ -682,10 +715,10 @@ impl Iterator for TagIterator {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.tags.is_null() { if self.tags.is_null() {
None None
} else if unsafe { notmuch_tags_valid(self.tags) } == 1 { } else if unsafe { call!(self.lib, notmuch_tags_valid)(self.tags) } == 1 {
let ret = Some(unsafe { CStr::from_ptr(notmuch_tags_get(self.tags)) }); let ret = Some(unsafe { CStr::from_ptr(call!(self.lib, notmuch_tags_get)(self.tags)) });
unsafe { unsafe {
notmuch_tags_move_to_next(self.tags); call!(self.lib, notmuch_tags_move_to_next)(self.tags);
} }
ret ret
} else { } else {

File diff suppressed because it is too large Load Diff