Load libnotmuch dynamically
parent
ac71d627f1
commit
303c530488
|
@ -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"
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
Loading…
Reference in New Issue