diff --git a/Makefile b/Makefile index d1b3a4cf..00ec1422 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ .POSIX: .SUFFIXES: meli: - cargo build --release + cargo build --features="$(MELI_FEATURES)" --release PREFIX=/usr/local diff --git a/README b/README index b0a18cbb..b80755de 100644 --- a/README +++ b/README @@ -54,6 +54,17 @@ BUILDING IN DEBIAN Building with Debian's packaged cargo might require the installation of these two packages: librust-openssl-sys-dev and librust-libdbus-sys-dev +BUILDING WITH NOTMUCH +===================== + +To use the optional notmuch backend feature, you must have libnotmuch installed in your system. In Debian-like systems, install the "libnotmuch" package. + +To build with notmuch support, prepend the environment variable "MELI_FEATURES='melib/notmuch_backend'" to your make invocation: + +# MELI_FEATURES="melib/notmuch_backend" make + +or if building directly with cargo, use the flag '--features="melib/notmuch_backend"'. + DEVELOPMENT =========== diff --git a/meli.1 b/meli.1 index fee7edd5..ca5187c0 100644 --- a/meli.1 +++ b/meli.1 @@ -139,8 +139,21 @@ To open a draft for editing later, select your draft in the mail listing and pre .Cm e Ns \&. .Sh SEARCH +Each e-mail storage backend has its default search method. +.Em IMAP +uses the SEARCH command, +.Em notmuch +uses libnotmuch and +.Em Maildir/mbox +have to perform a very slow and I/O bound linear search. Thus it is advised to use a cache on +.Em Maildir/mbox +accounts. .Nm Ns -, if built with sqlite3, includes the ability to perform full text search on the following fields: From, To, Cc, Bcc, In-Reply-To, References, Subject and Date. The message body (in plain text human readable form) and the flags can also be queried. To create the sqlite3 index issue command +, if built with sqlite3, includes the ability to perform full text search on the following fields: From, To, Cc, Bcc, In-Reply-To, References, Subject and Date. The message body (in plain text human readable form) and the flags can also be queried. To enable sqlite3 indexing for an account set +.Em cache_type +to +.Em sqlite3 +in the configuration file and to create the sqlite3 index issue command .Ic index Ar ACCOUNT_NAME Ns \&. To search in the message body type your keywords without any special formatting. diff --git a/meli.conf.5 b/meli.conf.5 index d8602cc7..b2c35c89 100644 --- a/meli.conf.5 +++ b/meli.conf.5 @@ -93,10 +93,10 @@ theme = "light" available options are listed below. .Sy default values are shown in parentheses. .Sh ACCOUNTS -.Bl -tag -width "danger_accept_invalid_certs boolean" -offset -indent +.Bl -tag -width "format String [maildir mbox imap notmuch]" -offset -indent .It Cm root_folder Ar String -the backend-specific path of the root_folder, usually INBOX -.It Cm format Ar String Op maildir mbox imap +the backend-specific path of the root_folder, usually INBOX. +.It Cm format Ar String Op maildir mbox imap notmuch the format of the mail backend. .It Cm subscribed_folders Ar [String,] an array of folder paths to display in the UI. Paths are relative to the root folder (eg "INBOX/Sent", not "Sent") @@ -129,6 +129,26 @@ choose which cache backend to use. Available options are 'none' and 'sqlite3' \&. .El .Pp +.Sh notmuch only +.Cm root_folder +points to the directory which contains the +.Pa .notmuch/ +subdirectory. notmuch folders are virtual, since they are defined by user-given notmuch queries. Thus you have to explicitly state the folders you want in the +.Cm folders +field and set the +.Ar query +property to each of them. Example: +.Pp +.Bd -literal +[accounts.notmuch] +format = "notmuch" +\&... + [accounts.notmuch.folders] + "INBOX" = { query="tag:inbox", subscribe = true } + "Drafts" = { query="tag:draft", subscribe = true } + "Sent" = { query="from:username@server.tld from:username2@server.tld", subscribe = true } +.Ed +.Sh IMAP only IMAP specific options are: .Bl -tag -width "danger_accept_invalid_certs boolean" -offset -indent .It Cm server_hostname Ar String diff --git a/melib/Cargo.toml b/melib/Cargo.toml index 1451db4a..b058c49e 100644 --- a/melib/Cargo.toml +++ b/melib/Cargo.toml @@ -4,6 +4,7 @@ version = "0.3.2" authors = ["Manos Pitsidianakis "] workspace = ".." edition = "2018" +build = "build.rs" [dependencies] bitflags = "1.0" @@ -34,4 +35,5 @@ unicode_algorithms = ["text_processing"] imap_backend = ["native-tls"] maildir_backend = ["notify", "notify-rust", "memmap"] mbox_backend = ["notify", "notify-rust", "memmap"] +notmuch_backend = [] vcard = [] diff --git a/melib/build.rs b/melib/build.rs new file mode 100644 index 00000000..95a56c58 --- /dev/null +++ b/melib/build.rs @@ -0,0 +1,6 @@ +fn main() { + #[cfg(feature = "notmuch_backend")] + { + println!("cargo:rustc-link-lib=notmuch"); + } +} diff --git a/melib/src/backends.rs b/melib/src/backends.rs index 9835a736..b7532eee 100644 --- a/melib/src/backends.rs +++ b/melib/src/backends.rs @@ -24,6 +24,10 @@ pub mod imap; pub mod maildir; #[cfg(feature = "mbox_backend")] pub mod mbox; +#[cfg(feature = "notmuch_backend")] +pub mod notmuch; +#[cfg(feature = "notmuch_backend")] +pub use self::notmuch::NotmuchDb; #[cfg(feature = "imap_backend")] pub use self::imap::ImapType; @@ -85,6 +89,13 @@ impl Backends { Box::new(|| Box::new(|f, i| Box::new(ImapType::new(f, i)))), ); } + #[cfg(feature = "notmuch_backend")] + { + b.register( + "notmuch".to_string(), + Box::new(|| Box::new(|f, i| Box::new(NotmuchDb::new(f, i)))), + ); + } b } diff --git a/melib/src/backends/maildir/backend.rs b/melib/src/backends/maildir/backend.rs index 7f198e3b..1a02e3a6 100644 --- a/melib/src/backends/maildir/backend.rs +++ b/melib/src/backends/maildir/backend.rs @@ -493,57 +493,7 @@ impl MailBackend for MaildirType { fn save(&self, bytes: &[u8], folder: &str, flags: Option) -> Result<()> { for f in self.folders.values() { if f.name == folder || f.path.to_str().unwrap() == folder { - let mut path = f.fs_path.clone(); - path.push("cur"); - { - let mut rand_buf = [0u8; 16]; - let mut f = fs::File::open("/dev/urandom") - .expect("Could not open /dev/urandom for reading"); - f.read_exact(&mut rand_buf) - .expect("Could not read from /dev/urandom/"); - let mut hostn_buf = String::with_capacity(256); - let mut f = fs::File::open("/etc/hostname") - .expect("Could not open /etc/hostname for reading"); - f.read_to_string(&mut hostn_buf) - .expect("Could not read from /etc/hostname"); - let timestamp = std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH) - .unwrap() - .as_millis(); - let mut filename = format!( - "{}.{:x}_{}.{}:2,", - timestamp, - u128::from_be_bytes(rand_buf), - std::process::id(), - hostn_buf.trim() - ); - if let Some(flags) = flags { - if !(flags & Flag::DRAFT).is_empty() { - filename.push('D'); - } - if !(flags & Flag::FLAGGED).is_empty() { - filename.push('F'); - } - if !(flags & Flag::PASSED).is_empty() { - filename.push('P'); - } - if !(flags & Flag::REPLIED).is_empty() { - filename.push('R'); - } - if !(flags & Flag::SEEN).is_empty() { - filename.push('S'); - } - if !(flags & Flag::TRASHED).is_empty() { - filename.push('T'); - } - } - path.push(filename); - } - debug!("saving at {}", path.display()); - let file = fs::File::create(path).unwrap(); - let mut writer = io::BufWriter::new(file); - writer.write_all(bytes).unwrap(); - return Ok(()); + return MaildirType::save_to_folder(f.fs_path.clone(), bytes, flags); } } @@ -863,6 +813,59 @@ impl MaildirType { }; w.build(handle) } + + pub fn save_to_folder(mut path: PathBuf, bytes: &[u8], flags: Option) -> Result<()> { + path.push("cur"); + { + let mut rand_buf = [0u8; 16]; + let mut f = + fs::File::open("/dev/urandom").expect("Could not open /dev/urandom for reading"); + f.read_exact(&mut rand_buf) + .expect("Could not read from /dev/urandom/"); + let mut hostn_buf = String::with_capacity(256); + let mut f = + fs::File::open("/etc/hostname").expect("Could not open /etc/hostname for reading"); + f.read_to_string(&mut hostn_buf) + .expect("Could not read from /etc/hostname"); + let timestamp = std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .unwrap() + .as_millis(); + let mut filename = format!( + "{}.{:x}_{}.{}:2,", + timestamp, + u128::from_be_bytes(rand_buf), + std::process::id(), + hostn_buf.trim() + ); + if let Some(flags) = flags { + if !(flags & Flag::DRAFT).is_empty() { + filename.push('D'); + } + if !(flags & Flag::FLAGGED).is_empty() { + filename.push('F'); + } + if !(flags & Flag::PASSED).is_empty() { + filename.push('P'); + } + if !(flags & Flag::REPLIED).is_empty() { + filename.push('R'); + } + if !(flags & Flag::SEEN).is_empty() { + filename.push('S'); + } + if !(flags & Flag::TRASHED).is_empty() { + filename.push('T'); + } + } + path.push(filename); + } + debug!("saving at {}", path.display()); + let file = fs::File::create(path).unwrap(); + let mut writer = io::BufWriter::new(file); + writer.write_all(bytes).unwrap(); + return Ok(()); + } } fn add_path_to_index( diff --git a/melib/src/backends/notmuch.rs b/melib/src/backends/notmuch.rs new file mode 100644 index 00000000..0daa05bc --- /dev/null +++ b/melib/src/backends/notmuch.rs @@ -0,0 +1,510 @@ +use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; +use crate::backends::FolderHash; +use crate::backends::{ + BackendFolder, BackendOp, Folder, FolderPermissions, MailBackend, RefreshEventConsumer, +}; +use crate::conf::AccountSettings; +use crate::email::{Envelope, EnvelopeHash, Flag}; +use crate::error::{MeliError, Result}; +use crate::shellexpand::ShellExpandTrait; +use fnv::FnvHashMap; +use std::collections::hash_map::DefaultHasher; +use std::ffi::CStr; +use std::hash::{Hash, Hasher}; +use std::io::Read; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, RwLock}; + +pub mod bindings; +use bindings::*; + +#[derive(Debug, Clone)] +struct DbWrapper { + inner: Arc>, + database_ph: std::marker::PhantomData<&'static mut notmuch_database_t>, +} + +unsafe impl Send for DbWrapper {} +unsafe impl Sync for DbWrapper {} + +#[derive(Debug)] +pub struct NotmuchDb { + database: DbWrapper, + folders: Arc>>, + index: Arc>>, + path: PathBuf, + save_messages_to: Option, +} + +unsafe impl Send for NotmuchDb {} +unsafe impl Sync for NotmuchDb {} + +impl Drop for NotmuchDb { + fn drop(&mut self) { + for f in self.folders.write().unwrap().values_mut() { + if let Some(query) = f.query.take() { + unsafe { + notmuch_query_destroy(query); + } + } + } + let inner = self.database.inner.write().unwrap(); + unsafe { + notmuch_database_close(*inner); + notmuch_database_destroy(*inner); + } + } +} + +#[derive(Debug, Clone, Default)] +struct NotmuchFolder { + hash: FolderHash, + children: Vec, + parent: Option, + name: String, + path: String, + query_str: String, + query: Option<*mut notmuch_query_t>, + phantom: std::marker::PhantomData<&'static mut notmuch_query_t>, +} + +impl BackendFolder for NotmuchFolder { + fn hash(&self) -> FolderHash { + self.hash + } + + fn name(&self) -> &str { + self.name.as_str() + } + + fn path(&self) -> &str { + self.path.as_str() + } + + fn change_name(&mut self, _s: &str) {} + + fn clone(&self) -> Folder { + Box::new(std::clone::Clone::clone(self)) + } + + fn children(&self) -> &[FolderHash] { + &self.children + } + + fn parent(&self) -> Option { + self.parent + } + + fn permissions(&self) -> FolderPermissions { + FolderPermissions::default() + } +} + +unsafe impl Send for NotmuchFolder {} +unsafe impl Sync for NotmuchFolder {} + +impl NotmuchDb { + pub fn new(s: &AccountSettings, _is_subscribed: Box bool>) -> Self { + let mut database: *mut notmuch_database_t = std::ptr::null_mut(); + let path = Path::new(s.root_folder.as_str()).expand().to_path_buf(); + if !path.exists() { + panic!( + "\"root_folder\" {} for account {} is not a valid path.", + s.root_folder.as_str(), + s.name() + ); + } + + let path_c = std::ffi::CString::new(path.to_str().unwrap()).unwrap(); + let path_ptr = path_c.as_ptr(); + let status = unsafe { + bindings::notmuch_database_open( + path_ptr, + notmuch_database_mode_t_NOTMUCH_DATABASE_MODE_READ_WRITE, + &mut database as *mut _, + ) + }; + if status != 0 { + panic!("notmuch_database_open returned {}.", status); + } + assert!(!database.is_null()); + let mut folders = FnvHashMap::default(); + for (k, f) in s.folders.iter() { + if let Some(query_str) = f.extra.get("query") { + let hash = { + let mut h = DefaultHasher::new(); + k.hash(&mut h); + h.finish() + }; + folders.insert( + hash, + NotmuchFolder { + hash, + name: k.to_string(), + path: k.to_string(), + children: vec![], + parent: None, + query: None, + query_str: query_str.to_string(), + phantom: std::marker::PhantomData, + }, + ); + } else { + eprintln!( + "notmuch folder configuration entry \"{}\" should have a \"query\" value set.", + k + ); + std::process::exit(1); + } + } + NotmuchDb { + database: DbWrapper { + inner: Arc::new(RwLock::new(database)), + database_ph: std::marker::PhantomData, + }, + path, + index: Arc::new(RwLock::new(Default::default())), + folders: Arc::new(RwLock::new(folders)), + save_messages_to: None, + } + } +} + +impl MailBackend for NotmuchDb { + fn is_online(&self) -> bool { + true + } + fn get(&mut self, folder: &Folder) -> Async>> { + let mut w = AsyncBuilder::new(); + let folder_hash = folder.hash(); + let database = self.database.clone(); + let index = self.index.clone(); + let folders = self.folders.clone(); + let handle = { + let tx = w.tx(); + let closure = move |_work_context| { + let mut ret: Vec = Vec::new(); + let database = database.clone(); + let database_lck = database.inner.read().unwrap(); + let folders = folders.clone(); + let tx = tx.clone(); + let mut folders_lck = folders.write().unwrap(); + let folder = folders_lck.get_mut(&folder_hash).unwrap(); + let query_str = std::ffi::CString::new(folder.query_str.as_str()).unwrap(); + let query: *mut notmuch_query_t = + unsafe { notmuch_query_create(*database_lck, query_str.as_ptr()) }; + if query.is_null() { + panic!("Out of memory."); + } + let mut messages: *mut notmuch_messages_t = std::ptr::null_mut(); + let status = + unsafe { notmuch_query_search_messages(query, &mut messages as *mut _) }; + if status != 0 { + panic!(status); + } + assert!(!messages.is_null()); + let iter = MessageIterator { messages }; + for message in iter { + let mut response = String::new(); + let fs_path = unsafe { notmuch_message_get_filename(message) }; + let mut f = match std::fs::File::open(unsafe { + CStr::from_ptr(fs_path) + .to_string_lossy() + .into_owned() + .as_str() + }) { + Ok(f) => f, + Err(e) => { + debug!("could not open fs_path {:?} {}", fs_path, e); + continue; + } + }; + response.clear(); + if let Err(e) = f.read_to_string(&mut response) { + debug!("could not read fs_path {:?} {}", fs_path, e); + continue; + } + let c_str = unsafe { CStr::from_ptr(fs_path) }; + let env_hash = { + let mut hasher = DefaultHasher::default(); + c_str.hash(&mut hasher); + hasher.finish() + }; + index.write().unwrap().insert(env_hash, c_str); + let op = Box::new(NotmuchOp { + database: database.clone(), + hash: env_hash, + index: index.clone(), + bytes: Some(response), + }); + if let Some(env) = Envelope::from_token(op, env_hash) { + ret.push(env); + } else { + debug!("could not parse path {:?}", c_str); + index.write().unwrap().remove(&env_hash); + } + } + folder.query = Some(query); + tx.send(AsyncStatus::Payload(Ok(ret))).unwrap(); + tx.send(AsyncStatus::Finished).unwrap(); + }; + Box::new(closure) + }; + w.build(handle) + } + + fn watch( + &self, + _sender: RefreshEventConsumer, + _work_context: WorkContext, + ) -> Result { + let handle = std::thread::Builder::new() + .name(format!( + "watching {}", + self.path.file_name().unwrap().to_str().unwrap() + )) + .spawn(move || {})?; + Ok(handle.thread().id()) + } + fn folders(&self) -> FnvHashMap { + self.folders + .read() + .unwrap() + .iter() + .map(|(k, f)| (*k, BackendFolder::clone(f))) + .collect() + } + fn operation(&self, hash: EnvelopeHash) -> Box { + Box::new(NotmuchOp { + database: self.database.clone(), + hash, + index: self.index.clone(), + bytes: None, + }) + } + + fn save(&self, bytes: &[u8], _folder: &str, flags: Option) -> Result<()> { + let mut path = self + .save_messages_to + .as_ref() + .unwrap_or(&self.path) + .to_path_buf(); + if !(path.ends_with("cur") || path.ends_with("new") || path.ends_with("tmp")) { + for d in &["cur", "new", "tmp"] { + path.push(d); + if !path.is_dir() { + return Err(MeliError::new(format!( + "{} is not a valid maildir folder", + path.display() + ))); + } + path.pop(); + } + path.push("cur"); + } + crate::backends::MaildirType::save_to_folder(path, bytes, flags) + } + + fn as_any(&self) -> &dyn::std::any::Any { + self + } +} + +#[derive(Debug)] +struct NotmuchOp { + hash: EnvelopeHash, + index: Arc>>, + database: DbWrapper, + bytes: Option, +} + +impl BackendOp for NotmuchOp { + fn description(&self) -> String { + String::new() + } + + fn as_bytes(&mut self) -> Result<&[u8]> { + let path = &self.index.read().unwrap()[&self.hash]; + let mut f = std::fs::File::open(path.to_str().unwrap())?; + let mut response = String::new(); + f.read_to_string(&mut response)?; + self.bytes = Some(response); + Ok(self.bytes.as_ref().unwrap().as_bytes()) + } + + fn fetch_headers(&mut self) -> Result<&[u8]> { + let raw = self.as_bytes()?; + let result = crate::email::parser::headers_raw(raw).to_full_result()?; + Ok(result) + } + + fn fetch_body(&mut self) -> Result<&[u8]> { + let raw = self.as_bytes()?; + let result = crate::email::parser::body_raw(raw).to_full_result()?; + Ok(result) + } + + fn fetch_flags(&self) -> Flag { + let mut flag = Flag::default(); + let path = self.index.read().unwrap()[&self.hash].to_str().unwrap(); + if !path.contains(":2,") { + return flag; + } + + for f in path.chars().rev() { + match f { + ',' => break, + 'D' => flag |= Flag::DRAFT, + 'F' => flag |= Flag::FLAGGED, + 'P' => flag |= Flag::PASSED, + 'R' => flag |= Flag::REPLIED, + 'S' => flag |= Flag::SEEN, + 'T' => flag |= Flag::TRASHED, + _ => { + debug!("DEBUG: in fetch_flags, path is {}", path); + } + } + } + + flag + } + + fn set_flag(&mut self, _envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> { + let mut message: *mut notmuch_message_t = std::ptr::null_mut(); + let mut index_lck = self.index.write().unwrap(); + unsafe { + notmuch_database_find_message_by_filename( + *self.database.inner.read().unwrap(), + index_lck[&self.hash].as_ptr(), + &mut message as *mut _, + ) + }; + if message.is_null() { + return Err(MeliError::new(format!( + "Error, message with path {:?} not found in notmuch database.", + index_lck[&self.hash] + ))); + } + + let tags = (TagIterator { + tags: unsafe { notmuch_message_get_tags(message) }, + }) + .collect::>(); + debug!(&tags); + + macro_rules! cstr { + ($l:literal) => { + CStr::from_bytes_with_nul_unchecked($l) + }; + } + macro_rules! add_tag { + ($l:literal) => { + unsafe { + if tags.contains(&cstr!($l)) { + return Ok(()); + } + if notmuch_message_add_tag(message, cstr!($l).as_ptr()) + != _notmuch_status_NOTMUCH_STATUS_SUCCESS + { + return Err(MeliError::new("Could not set tag.")); + } + } + }; + } + macro_rules! remove_tag { + ($l:literal) => { + unsafe { + if !tags.contains(&cstr!($l)) { + return Ok(()); + } + if notmuch_message_remove_tag(message, cstr!($l).as_ptr()) + != _notmuch_status_NOTMUCH_STATUS_SUCCESS + { + return Err(MeliError::new("Could not set tag.")); + } + } + }; + } + + match f { + Flag::DRAFT if value => add_tag!(b"draft\0"), + Flag::DRAFT => remove_tag!(b"draft\0"), + Flag::FLAGGED if value => add_tag!(b"flagged\0"), + Flag::FLAGGED => remove_tag!(b"flagged\0"), + Flag::PASSED if value => add_tag!(b"passed\0"), + Flag::PASSED => remove_tag!(b"passed\0"), + Flag::REPLIED if value => add_tag!(b"replied\0"), + Flag::REPLIED => remove_tag!(b"replied\0"), + Flag::SEEN if value => remove_tag!(b"unread\0"), + Flag::SEEN => add_tag!(b"unread\0"), + Flag::TRASHED if value => add_tag!(b"trashed\0"), + Flag::TRASHED => remove_tag!(b"trashed\0"), + _ => debug!("flags is {:?} value = {}", f, value), + } + + /* Update message filesystem path. */ + if unsafe { notmuch_message_tags_to_maildir_flags(message) } + != _notmuch_status_NOTMUCH_STATUS_SUCCESS + { + return Err(MeliError::new("Could not set tag.")); + } + + let fs_path = unsafe { notmuch_message_get_filename(message) }; + let c_str = unsafe { CStr::from_ptr(fs_path) }; + if let Some(p) = index_lck.get_mut(&self.hash) { + *p = c_str; + } + let new_hash = { + let mut hasher = DefaultHasher::default(); + c_str.hash(&mut hasher); + hasher.finish() + }; + index_lck.insert(new_hash, c_str); + + Ok(()) + } +} + +pub struct MessageIterator { + messages: *mut notmuch_messages_t, +} + +impl Iterator for MessageIterator { + type Item = *mut notmuch_message_t; + fn next(&mut self) -> Option { + if self.messages.is_null() { + None + } else if unsafe { notmuch_messages_valid(self.messages) } == 1 { + let ret = Some(unsafe { notmuch_messages_get(self.messages) }); + unsafe { + notmuch_messages_move_to_next(self.messages); + } + ret + } else { + self.messages = std::ptr::null_mut(); + None + } + } +} + +pub struct TagIterator { + tags: *mut notmuch_tags_t, +} + +impl Iterator for TagIterator { + type Item = &'static CStr; + fn next(&mut self) -> Option { + if self.tags.is_null() { + None + } else if unsafe { notmuch_tags_valid(self.tags) } == 1 { + let ret = Some(unsafe { CStr::from_ptr(notmuch_tags_get(self.tags)) }); + unsafe { + notmuch_tags_move_to_next(self.tags); + } + ret + } else { + self.tags = std::ptr::null_mut(); + None + } + } +} diff --git a/melib/src/backends/notmuch/bindings.rs b/melib/src/backends/notmuch/bindings.rs new file mode 100644 index 00000000..405e7470 --- /dev/null +++ b/melib/src/backends/notmuch/bindings.rs @@ -0,0 +1,2708 @@ +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] +#![allow(dead_code)] +#![link(name = "notmuch")] + +/* automatically generated by rust-bindgen */ + +pub const _TIME_H: u32 = 1; +pub const _FEATURES_H: u32 = 1; +pub const _DEFAULT_SOURCE: u32 = 1; +pub const __USE_ISOC11: u32 = 1; +pub const __USE_ISOC99: u32 = 1; +pub const __USE_ISOC95: u32 = 1; +pub const __USE_POSIX_IMPLICITLY: u32 = 1; +pub const _POSIX_SOURCE: u32 = 1; +pub const _POSIX_C_SOURCE: u32 = 200809; +pub const __USE_POSIX: u32 = 1; +pub const __USE_POSIX2: u32 = 1; +pub const __USE_POSIX199309: u32 = 1; +pub const __USE_POSIX199506: u32 = 1; +pub const __USE_XOPEN2K: u32 = 1; +pub const __USE_XOPEN2K8: u32 = 1; +pub const _ATFILE_SOURCE: u32 = 1; +pub const __USE_MISC: u32 = 1; +pub const __USE_ATFILE: u32 = 1; +pub const __USE_FORTIFY_LEVEL: u32 = 0; +pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0; +pub const _STDC_PREDEF_H: u32 = 1; +pub const __STDC_IEC_559__: u32 = 1; +pub const __STDC_IEC_559_COMPLEX__: u32 = 1; +pub const __STDC_ISO_10646__: u32 = 201706; +pub const __GNU_LIBRARY__: u32 = 6; +pub const __GLIBC__: u32 = 2; +pub const __GLIBC_MINOR__: u32 = 28; +pub const _SYS_CDEFS_H: u32 = 1; +pub const __glibc_c99_flexarr_available: u32 = 1; +pub const __WORDSIZE: u32 = 64; +pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1; +pub const __SYSCALL_WORDSIZE: u32 = 64; +pub const __HAVE_GENERIC_SELECTION: u32 = 1; +pub const _BITS_TIME_H: u32 = 1; +pub const _BITS_TYPES_H: u32 = 1; +pub const _BITS_TYPESIZES_H: u32 = 1; +pub const __OFF_T_MATCHES_OFF64_T: u32 = 1; +pub const __INO_T_MATCHES_INO64_T: u32 = 1; +pub const __RLIM_T_MATCHES_RLIM64_T: u32 = 1; +pub const __FD_SETSIZE: u32 = 1024; +pub const CLOCK_REALTIME: u32 = 0; +pub const CLOCK_MONOTONIC: u32 = 1; +pub const CLOCK_PROCESS_CPUTIME_ID: u32 = 2; +pub const CLOCK_THREAD_CPUTIME_ID: u32 = 3; +pub const CLOCK_MONOTONIC_RAW: u32 = 4; +pub const CLOCK_REALTIME_COARSE: u32 = 5; +pub const CLOCK_MONOTONIC_COARSE: u32 = 6; +pub const CLOCK_BOOTTIME: u32 = 7; +pub const CLOCK_REALTIME_ALARM: u32 = 8; +pub const CLOCK_BOOTTIME_ALARM: u32 = 9; +pub const CLOCK_TAI: u32 = 11; +pub const TIMER_ABSTIME: u32 = 1; +pub const __clock_t_defined: u32 = 1; +pub const __time_t_defined: u32 = 1; +pub const __struct_tm_defined: u32 = 1; +pub const _STRUCT_TIMESPEC: u32 = 1; +pub const __clockid_t_defined: u32 = 1; +pub const __timer_t_defined: u32 = 1; +pub const __itimerspec_defined: u32 = 1; +pub const _BITS_TYPES_LOCALE_T_H: u32 = 1; +pub const _BITS_TYPES___LOCALE_T_H: u32 = 1; +pub const TIME_UTC: u32 = 1; +pub const FALSE: u32 = 0; +pub const TRUE: u32 = 1; +pub const LIBNOTMUCH_MAJOR_VERSION: u32 = 5; +pub const LIBNOTMUCH_MINOR_VERSION: u32 = 2; +pub const LIBNOTMUCH_MICRO_VERSION: u32 = 0; +pub const NOTMUCH_TAG_MAX: u32 = 200; +pub type __u_char = ::std::os::raw::c_uchar; +pub type __u_short = ::std::os::raw::c_ushort; +pub type __u_int = ::std::os::raw::c_uint; +pub type __u_long = ::std::os::raw::c_ulong; +pub type __int8_t = ::std::os::raw::c_schar; +pub type __uint8_t = ::std::os::raw::c_uchar; +pub type __int16_t = ::std::os::raw::c_short; +pub type __uint16_t = ::std::os::raw::c_ushort; +pub type __int32_t = ::std::os::raw::c_int; +pub type __uint32_t = ::std::os::raw::c_uint; +pub type __int64_t = ::std::os::raw::c_long; +pub type __uint64_t = ::std::os::raw::c_ulong; +pub type __int_least8_t = __int8_t; +pub type __uint_least8_t = __uint8_t; +pub type __int_least16_t = __int16_t; +pub type __uint_least16_t = __uint16_t; +pub type __int_least32_t = __int32_t; +pub type __uint_least32_t = __uint32_t; +pub type __int_least64_t = __int64_t; +pub type __uint_least64_t = __uint64_t; +pub type __quad_t = ::std::os::raw::c_long; +pub type __u_quad_t = ::std::os::raw::c_ulong; +pub type __intmax_t = ::std::os::raw::c_long; +pub type __uintmax_t = ::std::os::raw::c_ulong; +pub type __dev_t = ::std::os::raw::c_ulong; +pub type __uid_t = ::std::os::raw::c_uint; +pub type __gid_t = ::std::os::raw::c_uint; +pub type __ino_t = ::std::os::raw::c_ulong; +pub type __ino64_t = ::std::os::raw::c_ulong; +pub type __mode_t = ::std::os::raw::c_uint; +pub type __nlink_t = ::std::os::raw::c_ulong; +pub type __off_t = ::std::os::raw::c_long; +pub type __off64_t = ::std::os::raw::c_long; +pub type __pid_t = ::std::os::raw::c_int; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __fsid_t { + pub __val: [::std::os::raw::c_int; 2usize], +} +#[test] +fn bindgen_test_layout___fsid_t() { + assert_eq!( + ::std::mem::size_of::<__fsid_t>(), + 8usize, + concat!("Size of: ", stringify!(__fsid_t)) + ); + assert_eq!( + ::std::mem::align_of::<__fsid_t>(), + 4usize, + concat!("Alignment of ", stringify!(__fsid_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__fsid_t>())).__val as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__fsid_t), + "::", + stringify!(__val) + ) + ); +} +pub type __clock_t = ::std::os::raw::c_long; +pub type __rlim_t = ::std::os::raw::c_ulong; +pub type __rlim64_t = ::std::os::raw::c_ulong; +pub type __id_t = ::std::os::raw::c_uint; +pub type __time_t = ::std::os::raw::c_long; +pub type __useconds_t = ::std::os::raw::c_uint; +pub type __suseconds_t = ::std::os::raw::c_long; +pub type __daddr_t = ::std::os::raw::c_int; +pub type __key_t = ::std::os::raw::c_int; +pub type __clockid_t = ::std::os::raw::c_int; +pub type __timer_t = *mut ::std::os::raw::c_void; +pub type __blksize_t = ::std::os::raw::c_long; +pub type __blkcnt_t = ::std::os::raw::c_long; +pub type __blkcnt64_t = ::std::os::raw::c_long; +pub type __fsblkcnt_t = ::std::os::raw::c_ulong; +pub type __fsblkcnt64_t = ::std::os::raw::c_ulong; +pub type __fsfilcnt_t = ::std::os::raw::c_ulong; +pub type __fsfilcnt64_t = ::std::os::raw::c_ulong; +pub type __fsword_t = ::std::os::raw::c_long; +pub type __ssize_t = ::std::os::raw::c_long; +pub type __syscall_slong_t = ::std::os::raw::c_long; +pub type __syscall_ulong_t = ::std::os::raw::c_ulong; +pub type __loff_t = __off64_t; +pub type __caddr_t = *mut ::std::os::raw::c_char; +pub type __intptr_t = ::std::os::raw::c_long; +pub type __socklen_t = ::std::os::raw::c_uint; +pub type __sig_atomic_t = ::std::os::raw::c_int; +pub type clock_t = __clock_t; +pub type time_t = __time_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct tm { + pub tm_sec: ::std::os::raw::c_int, + pub tm_min: ::std::os::raw::c_int, + pub tm_hour: ::std::os::raw::c_int, + pub tm_mday: ::std::os::raw::c_int, + pub tm_mon: ::std::os::raw::c_int, + pub tm_year: ::std::os::raw::c_int, + pub tm_wday: ::std::os::raw::c_int, + pub tm_yday: ::std::os::raw::c_int, + pub tm_isdst: ::std::os::raw::c_int, + pub tm_gmtoff: ::std::os::raw::c_long, + pub tm_zone: *const ::std::os::raw::c_char, +} +#[test] +fn bindgen_test_layout_tm() { + assert_eq!( + ::std::mem::size_of::(), + 56usize, + concat!("Size of: ", stringify!(tm)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(tm)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).tm_sec as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_sec) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).tm_min as *const _ as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_min) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).tm_hour as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_hour) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).tm_mday as *const _ as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_mday) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).tm_mon as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_mon) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).tm_year as *const _ as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_year) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).tm_wday as *const _ as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_wday) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).tm_yday as *const _ as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_yday) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).tm_isdst as *const _ as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_isdst) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).tm_gmtoff as *const _ as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_gmtoff) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).tm_zone as *const _ as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_zone) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct timespec { + pub tv_sec: __time_t, + pub tv_nsec: __syscall_slong_t, +} +#[test] +fn bindgen_test_layout_timespec() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(timespec)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(timespec)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).tv_sec as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(timespec), + "::", + stringify!(tv_sec) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).tv_nsec as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(timespec), + "::", + stringify!(tv_nsec) + ) + ); +} +pub type clockid_t = __clockid_t; +pub type timer_t = __timer_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct itimerspec { + pub it_interval: timespec, + pub it_value: timespec, +} +#[test] +fn bindgen_test_layout_itimerspec() { + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(itimerspec)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(itimerspec)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).it_interval as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(itimerspec), + "::", + stringify!(it_interval) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).it_value as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(itimerspec), + "::", + stringify!(it_value) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sigevent { + _unused: [u8; 0], +} +pub type pid_t = __pid_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __locale_struct { + pub __locales: [*mut __locale_data; 13usize], + pub __ctype_b: *const ::std::os::raw::c_ushort, + pub __ctype_tolower: *const ::std::os::raw::c_int, + pub __ctype_toupper: *const ::std::os::raw::c_int, + pub __names: [*const ::std::os::raw::c_char; 13usize], +} +#[test] +fn bindgen_test_layout___locale_struct() { + assert_eq!( + ::std::mem::size_of::<__locale_struct>(), + 232usize, + concat!("Size of: ", stringify!(__locale_struct)) + ); + assert_eq!( + ::std::mem::align_of::<__locale_struct>(), + 8usize, + concat!("Alignment of ", stringify!(__locale_struct)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__locale_struct>())).__locales as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__locale_struct), + "::", + stringify!(__locales) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__locale_struct>())).__ctype_b as *const _ as usize }, + 104usize, + concat!( + "Offset of field: ", + stringify!(__locale_struct), + "::", + stringify!(__ctype_b) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__locale_struct>())).__ctype_tolower as *const _ as usize }, + 112usize, + concat!( + "Offset of field: ", + stringify!(__locale_struct), + "::", + stringify!(__ctype_tolower) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__locale_struct>())).__ctype_toupper as *const _ as usize }, + 120usize, + concat!( + "Offset of field: ", + stringify!(__locale_struct), + "::", + stringify!(__ctype_toupper) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__locale_struct>())).__names as *const _ as usize }, + 128usize, + concat!( + "Offset of field: ", + stringify!(__locale_struct), + "::", + stringify!(__names) + ) + ); +} +pub type __locale_t = *mut __locale_struct; +pub type locale_t = __locale_t; +extern "C" { + pub fn clock() -> clock_t; +} +extern "C" { + pub fn time(__timer: *mut time_t) -> time_t; +} +extern "C" { + pub fn difftime(__time1: time_t, __time0: time_t) -> f64; +} +extern "C" { + pub fn mktime(__tp: *mut tm) -> time_t; +} +extern "C" { + pub fn strftime( + __s: *mut ::std::os::raw::c_char, + __maxsize: usize, + __format: *const ::std::os::raw::c_char, + __tp: *const tm, + ) -> usize; +} +extern "C" { + pub fn strftime_l( + __s: *mut ::std::os::raw::c_char, + __maxsize: usize, + __format: *const ::std::os::raw::c_char, + __tp: *const tm, + __loc: locale_t, + ) -> usize; +} +extern "C" { + pub fn gmtime(__timer: *const time_t) -> *mut tm; +} +extern "C" { + pub fn localtime(__timer: *const time_t) -> *mut tm; +} +extern "C" { + pub fn gmtime_r(__timer: *const time_t, __tp: *mut tm) -> *mut tm; +} +extern "C" { + pub fn localtime_r(__timer: *const time_t, __tp: *mut tm) -> *mut tm; +} +extern "C" { + pub fn asctime(__tp: *const tm) -> *mut ::std::os::raw::c_char; +} +extern "C" { + pub fn ctime(__timer: *const time_t) -> *mut ::std::os::raw::c_char; +} +extern "C" { + pub fn asctime_r( + __tp: *const tm, + __buf: *mut ::std::os::raw::c_char, + ) -> *mut ::std::os::raw::c_char; +} +extern "C" { + pub fn ctime_r( + __timer: *const time_t, + __buf: *mut ::std::os::raw::c_char, + ) -> *mut ::std::os::raw::c_char; +} +extern "C" { + pub static mut __tzname: [*mut ::std::os::raw::c_char; 2usize]; +} +extern "C" { + pub static mut __daylight: ::std::os::raw::c_int; +} +extern "C" { + pub static mut __timezone: ::std::os::raw::c_long; +} +extern "C" { + pub static mut tzname: [*mut ::std::os::raw::c_char; 2usize]; +} +extern "C" { + pub fn tzset(); +} +extern "C" { + pub static mut daylight: ::std::os::raw::c_int; +} +extern "C" { + pub static mut timezone: ::std::os::raw::c_long; +} +extern "C" { + pub fn stime(__when: *const time_t) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn timegm(__tp: *mut tm) -> time_t; +} +extern "C" { + pub fn timelocal(__tp: *mut tm) -> time_t; +} +extern "C" { + pub fn dysize(__year: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn nanosleep( + __requested_time: *const timespec, + __remaining: *mut timespec, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn clock_getres(__clock_id: clockid_t, __res: *mut timespec) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn clock_gettime(__clock_id: clockid_t, __tp: *mut timespec) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn clock_settime(__clock_id: clockid_t, __tp: *const timespec) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn clock_nanosleep( + __clock_id: clockid_t, + __flags: ::std::os::raw::c_int, + __req: *const timespec, + __rem: *mut timespec, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn clock_getcpuclockid(__pid: pid_t, __clock_id: *mut clockid_t) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn timer_create( + __clock_id: clockid_t, + __evp: *mut sigevent, + __timerid: *mut timer_t, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn timer_delete(__timerid: timer_t) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn timer_settime( + __timerid: timer_t, + __flags: ::std::os::raw::c_int, + __value: *const itimerspec, + __ovalue: *mut itimerspec, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn timer_gettime(__timerid: timer_t, __value: *mut itimerspec) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn timer_getoverrun(__timerid: timer_t) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn timespec_get( + __ts: *mut timespec, + __base: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +#[doc = " Notmuch boolean type."] +pub type notmuch_bool_t = ::std::os::raw::c_int; +#[doc = " No error occurred."] +pub const _notmuch_status_NOTMUCH_STATUS_SUCCESS: _notmuch_status = 0; +#[doc = " Out of memory."] +pub const _notmuch_status_NOTMUCH_STATUS_OUT_OF_MEMORY: _notmuch_status = 1; +#[doc = " An attempt was made to write to a database opened in read-only"] +#[doc = " mode."] +pub const _notmuch_status_NOTMUCH_STATUS_READ_ONLY_DATABASE: _notmuch_status = 2; +#[doc = " A Xapian exception occurred."] +#[doc = ""] +#[doc = " @todo We don't really want to expose this lame XAPIAN_EXCEPTION"] +#[doc = " value. Instead we should map to things like DATABASE_LOCKED or"] +#[doc = " whatever."] +pub const _notmuch_status_NOTMUCH_STATUS_XAPIAN_EXCEPTION: _notmuch_status = 3; +#[doc = " An error occurred trying to read or write to a file (this could"] +#[doc = " be file not found, permission denied, etc.)"] +pub const _notmuch_status_NOTMUCH_STATUS_FILE_ERROR: _notmuch_status = 4; +#[doc = " A file was presented that doesn't appear to be an email"] +#[doc = " message."] +pub const _notmuch_status_NOTMUCH_STATUS_FILE_NOT_EMAIL: _notmuch_status = 5; +#[doc = " A file contains a message ID that is identical to a message"] +#[doc = " already in the database."] +pub const _notmuch_status_NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: _notmuch_status = 6; +#[doc = " The user erroneously passed a NULL pointer to a notmuch"] +#[doc = " function."] +pub const _notmuch_status_NOTMUCH_STATUS_NULL_POINTER: _notmuch_status = 7; +#[doc = " A tag value is too long (exceeds NOTMUCH_TAG_MAX)."] +pub const _notmuch_status_NOTMUCH_STATUS_TAG_TOO_LONG: _notmuch_status = 8; +#[doc = " The notmuch_message_thaw function has been called more times"] +#[doc = " than notmuch_message_freeze."] +pub const _notmuch_status_NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: _notmuch_status = 9; +#[doc = " notmuch_database_end_atomic has been called more times than"] +#[doc = " notmuch_database_begin_atomic."] +pub const _notmuch_status_NOTMUCH_STATUS_UNBALANCED_ATOMIC: _notmuch_status = 10; +#[doc = " The operation is not supported."] +pub const _notmuch_status_NOTMUCH_STATUS_UNSUPPORTED_OPERATION: _notmuch_status = 11; +#[doc = " The operation requires a database upgrade."] +pub const _notmuch_status_NOTMUCH_STATUS_UPGRADE_REQUIRED: _notmuch_status = 12; +#[doc = " There is a problem with the proposed path, e.g. a relative path"] +#[doc = " passed to a function expecting an absolute path."] +pub const _notmuch_status_NOTMUCH_STATUS_PATH_ERROR: _notmuch_status = 13; +#[doc = " The requested operation was ignored. Depending on the function,"] +#[doc = " this may not be an actual error."] +pub const _notmuch_status_NOTMUCH_STATUS_IGNORED: _notmuch_status = 14; +#[doc = " One of the arguments violates the preconditions for the"] +#[doc = " function, in a way not covered by a more specific argument."] +pub const _notmuch_status_NOTMUCH_STATUS_ILLEGAL_ARGUMENT: _notmuch_status = 15; +#[doc = " A MIME object claimed to have cryptographic protection which"] +#[doc = " notmuch tried to handle, but the protocol was not specified in"] +#[doc = " an intelligible way."] +pub const _notmuch_status_NOTMUCH_STATUS_MALFORMED_CRYPTO_PROTOCOL: _notmuch_status = 16; +#[doc = " Notmuch attempted to do crypto processing, but could not"] +#[doc = " initialize the engine needed to do so."] +pub const _notmuch_status_NOTMUCH_STATUS_FAILED_CRYPTO_CONTEXT_CREATION: _notmuch_status = 17; +#[doc = " A MIME object claimed to have cryptographic protection, and"] +#[doc = " notmuch attempted to process it, but the specific protocol was"] +#[doc = " something that notmuch doesn't know how to handle."] +pub const _notmuch_status_NOTMUCH_STATUS_UNKNOWN_CRYPTO_PROTOCOL: _notmuch_status = 18; +#[doc = " Not an actual status value. Just a way to find out how many"] +#[doc = " valid status values there are."] +pub const _notmuch_status_NOTMUCH_STATUS_LAST_STATUS: _notmuch_status = 19; +#[doc = " Status codes used for the return values of most functions."] +#[doc = ""] +#[doc = " A zero value (NOTMUCH_STATUS_SUCCESS) indicates that the function"] +#[doc = " completed without error. Any other value indicates an error."] +pub type _notmuch_status = u32; +pub use self::_notmuch_status as notmuch_status_t; +extern "C" { + #[doc = " Get a string representation of a notmuch_status_t value."] + #[doc = ""] + #[doc = " The result is read-only."] + pub fn notmuch_status_to_string(status: notmuch_status_t) -> *const ::std::os::raw::c_char; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _notmuch_database { + _unused: [u8; 0], +} +pub type notmuch_database_t = _notmuch_database; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _notmuch_query { + _unused: [u8; 0], +} +pub type notmuch_query_t = _notmuch_query; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _notmuch_threads { + _unused: [u8; 0], +} +pub type notmuch_threads_t = _notmuch_threads; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _notmuch_thread { + _unused: [u8; 0], +} +pub type notmuch_thread_t = _notmuch_thread; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _notmuch_messages { + _unused: [u8; 0], +} +pub type notmuch_messages_t = _notmuch_messages; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _notmuch_message { + _unused: [u8; 0], +} +pub type notmuch_message_t = _notmuch_message; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _notmuch_tags { + _unused: [u8; 0], +} +pub type notmuch_tags_t = _notmuch_tags; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _notmuch_directory { + _unused: [u8; 0], +} +pub type notmuch_directory_t = _notmuch_directory; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _notmuch_filenames { + _unused: [u8; 0], +} +pub type notmuch_filenames_t = _notmuch_filenames; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _notmuch_config_list { + _unused: [u8; 0], +} +pub type notmuch_config_list_t = _notmuch_config_list; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _notmuch_indexopts { + _unused: [u8; 0], +} +pub type notmuch_indexopts_t = _notmuch_indexopts; +extern "C" { + #[doc = " Create a new, empty notmuch database located at 'path'."] + #[doc = ""] + #[doc = " The path should be a top-level directory to a collection of"] + #[doc = " plain-text email messages (one message per file). This call will"] + #[doc = " create a new \".notmuch\" directory within 'path' where notmuch will"] + #[doc = " store its data."] + #[doc = ""] + #[doc = " After a successful call to notmuch_database_create, the returned"] + #[doc = " database will be open so the caller should call"] + #[doc = " notmuch_database_destroy when finished with it."] + #[doc = ""] + #[doc = " The database will not yet have any data in it"] + #[doc = " (notmuch_database_create itself is a very cheap function). Messages"] + #[doc = " contained within 'path' can be added to the database by calling"] + #[doc = " notmuch_database_index_file."] + #[doc = ""] + #[doc = " In case of any failure, this function returns an error status and"] + #[doc = " sets *database to NULL (after printing an error message on stderr)."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: Successfully created the database."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_NULL_POINTER: The given 'path' argument is NULL."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_FILE_ERROR: An error occurred trying to create the"] + #[doc = "\tdatabase file (such as permission denied, or file not found,"] + #[doc = "\tetc.), or the database already exists."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred."] + pub fn notmuch_database_create( + path: *const ::std::os::raw::c_char, + database: *mut *mut notmuch_database_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Like notmuch_database_create, except optionally return an error"] + #[doc = " message. This message is allocated by malloc and should be freed by"] + #[doc = " the caller."] + pub fn notmuch_database_create_verbose( + path: *const ::std::os::raw::c_char, + database: *mut *mut notmuch_database_t, + error_message: *mut *mut ::std::os::raw::c_char, + ) -> notmuch_status_t; +} +#[doc = " Open database for reading only."] +pub const notmuch_database_mode_t_NOTMUCH_DATABASE_MODE_READ_ONLY: notmuch_database_mode_t = 0; +#[doc = " Open database for reading and writing."] +pub const notmuch_database_mode_t_NOTMUCH_DATABASE_MODE_READ_WRITE: notmuch_database_mode_t = 1; +#[doc = " Database open mode for notmuch_database_open."] +pub type notmuch_database_mode_t = u32; +extern "C" { + #[doc = " Open an existing notmuch database located at 'path'."] + #[doc = ""] + #[doc = " The database should have been created at some time in the past,"] + #[doc = " (not necessarily by this process), by calling"] + #[doc = " notmuch_database_create with 'path'. By default the database should be"] + #[doc = " opened for reading only. In order to write to the database you need to"] + #[doc = " pass the NOTMUCH_DATABASE_MODE_READ_WRITE mode."] + #[doc = ""] + #[doc = " An existing notmuch database can be identified by the presence of a"] + #[doc = " directory named \".notmuch\" below 'path'."] + #[doc = ""] + #[doc = " The caller should call notmuch_database_destroy when finished with"] + #[doc = " this database."] + #[doc = ""] + #[doc = " In case of any failure, this function returns an error status and"] + #[doc = " sets *database to NULL (after printing an error message on stderr)."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: Successfully opened the database."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_NULL_POINTER: The given 'path' argument is NULL."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_FILE_ERROR: An error occurred trying to open the"] + #[doc = "\tdatabase file (such as permission denied, or file not found,"] + #[doc = "\tetc.), or the database version is unknown."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred."] + pub fn notmuch_database_open( + path: *const ::std::os::raw::c_char, + mode: notmuch_database_mode_t, + database: *mut *mut notmuch_database_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Like notmuch_database_open, except optionally return an error"] + #[doc = " message. This message is allocated by malloc and should be freed by"] + #[doc = " the caller."] + pub fn notmuch_database_open_verbose( + path: *const ::std::os::raw::c_char, + mode: notmuch_database_mode_t, + database: *mut *mut notmuch_database_t, + error_message: *mut *mut ::std::os::raw::c_char, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Retrieve last status string for given database."] + #[doc = ""] + pub fn notmuch_database_status_string( + notmuch: *const notmuch_database_t, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Commit changes and close the given notmuch database."] + #[doc = ""] + #[doc = " After notmuch_database_close has been called, calls to other"] + #[doc = " functions on objects derived from this database may either behave"] + #[doc = " as if the database had not been closed (e.g., if the required data"] + #[doc = " has been cached) or may fail with a"] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION. The only further operation"] + #[doc = " permitted on the database itself is to call"] + #[doc = " notmuch_database_destroy."] + #[doc = ""] + #[doc = " notmuch_database_close can be called multiple times. Later calls"] + #[doc = " have no effect."] + #[doc = ""] + #[doc = " For writable databases, notmuch_database_close commits all changes"] + #[doc = " to disk before closing the database. If the caller is currently in"] + #[doc = " an atomic section (there was a notmuch_database_begin_atomic"] + #[doc = " without a matching notmuch_database_end_atomic), this will discard"] + #[doc = " changes made in that atomic section (but still commit changes made"] + #[doc = " prior to entering the atomic section)."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: Successfully closed the database."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred; the"] + #[doc = "\tdatabase has been closed but there are no guarantees the"] + #[doc = "\tchanges to the database, if any, have been flushed to disk."] + pub fn notmuch_database_close(database: *mut notmuch_database_t) -> notmuch_status_t; +} +#[doc = " A callback invoked by notmuch_database_compact to notify the user"] +#[doc = " of the progress of the compaction process."] +pub type notmuch_compact_status_cb_t = ::std::option::Option< + unsafe extern "C" fn( + message: *const ::std::os::raw::c_char, + closure: *mut ::std::os::raw::c_void, + ), +>; +extern "C" { + #[doc = " Compact a notmuch database, backing up the original database to the"] + #[doc = " given path."] + #[doc = ""] + #[doc = " The database will be opened with NOTMUCH_DATABASE_MODE_READ_WRITE"] + #[doc = " during the compaction process to ensure no writes are made."] + #[doc = ""] + #[doc = " If the optional callback function 'status_cb' is non-NULL, it will"] + #[doc = " be called with diagnostic and informational messages. The argument"] + #[doc = " 'closure' is passed verbatim to any callback invoked."] + pub fn notmuch_database_compact( + path: *const ::std::os::raw::c_char, + backup_path: *const ::std::os::raw::c_char, + status_cb: notmuch_compact_status_cb_t, + closure: *mut ::std::os::raw::c_void, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Destroy the notmuch database, closing it if necessary and freeing"] + #[doc = " all associated resources."] + #[doc = ""] + #[doc = " Return value as in notmuch_database_close if the database was open;"] + #[doc = " notmuch_database_destroy itself has no failure modes."] + pub fn notmuch_database_destroy(database: *mut notmuch_database_t) -> notmuch_status_t; +} +extern "C" { + #[doc = " Return the database path of the given database."] + #[doc = ""] + #[doc = " The return value is a string owned by notmuch so should not be"] + #[doc = " modified nor freed by the caller."] + pub fn notmuch_database_get_path( + database: *mut notmuch_database_t, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Return the database format version of the given database."] + pub fn notmuch_database_get_version( + database: *mut notmuch_database_t, + ) -> ::std::os::raw::c_uint; +} +extern "C" { + #[doc = " Can the database be upgraded to a newer database version?"] + #[doc = ""] + #[doc = " If this function returns TRUE, then the caller may call"] + #[doc = " notmuch_database_upgrade to upgrade the database. If the caller"] + #[doc = " does not upgrade an out-of-date database, then some functions may"] + #[doc = " fail with NOTMUCH_STATUS_UPGRADE_REQUIRED. This always returns"] + #[doc = " FALSE for a read-only database because there's no way to upgrade a"] + #[doc = " read-only database."] + pub fn notmuch_database_needs_upgrade(database: *mut notmuch_database_t) -> notmuch_bool_t; +} +extern "C" { + #[doc = " Upgrade the current database to the latest supported version."] + #[doc = ""] + #[doc = " This ensures that all current notmuch functionality will be"] + #[doc = " available on the database. After opening a database in read-write"] + #[doc = " mode, it is recommended that clients check if an upgrade is needed"] + #[doc = " (notmuch_database_needs_upgrade) and if so, upgrade with this"] + #[doc = " function before making any modifications. If"] + #[doc = " notmuch_database_needs_upgrade returns FALSE, this will be a no-op."] + #[doc = ""] + #[doc = " The optional progress_notify callback can be used by the caller to"] + #[doc = " provide progress indication to the user. If non-NULL it will be"] + #[doc = " called periodically with 'progress' as a floating-point value in"] + #[doc = " the range of [0.0 .. 1.0] indicating the progress made so far in"] + #[doc = " the upgrade process. The argument 'closure' is passed verbatim to"] + #[doc = " any callback invoked."] + pub fn notmuch_database_upgrade( + database: *mut notmuch_database_t, + progress_notify: ::std::option::Option< + unsafe extern "C" fn(closure: *mut ::std::os::raw::c_void, progress: f64), + >, + closure: *mut ::std::os::raw::c_void, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Begin an atomic database operation."] + #[doc = ""] + #[doc = " Any modifications performed between a successful begin and a"] + #[doc = " notmuch_database_end_atomic will be applied to the database"] + #[doc = " atomically. Note that, unlike a typical database transaction, this"] + #[doc = " only ensures atomicity, not durability; neither begin nor end"] + #[doc = " necessarily flush modifications to disk."] + #[doc = ""] + #[doc = " Atomic sections may be nested. begin_atomic and end_atomic must"] + #[doc = " always be called in pairs."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: Successfully entered atomic section."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred;"] + #[doc = "\tatomic section not entered."] + pub fn notmuch_database_begin_atomic(notmuch: *mut notmuch_database_t) -> notmuch_status_t; +} +extern "C" { + #[doc = " Indicate the end of an atomic database operation."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: Successfully completed atomic section."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred;"] + #[doc = "\tatomic section not ended."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_UNBALANCED_ATOMIC: The database is not currently in"] + #[doc = "\tan atomic section."] + pub fn notmuch_database_end_atomic(notmuch: *mut notmuch_database_t) -> notmuch_status_t; +} +extern "C" { + #[doc = " Return the committed database revision and UUID."] + #[doc = ""] + #[doc = " The database revision number increases monotonically with each"] + #[doc = " commit to the database. Hence, all messages and message changes"] + #[doc = " committed to the database (that is, visible to readers) have a last"] + #[doc = " modification revision <= the committed database revision. Any"] + #[doc = " messages committed in the future will be assigned a modification"] + #[doc = " revision > the committed database revision."] + #[doc = ""] + #[doc = " The UUID is a NUL-terminated opaque string that uniquely identifies"] + #[doc = " this database. Two revision numbers are only comparable if they"] + #[doc = " have the same database UUID."] + pub fn notmuch_database_get_revision( + notmuch: *mut notmuch_database_t, + uuid: *mut *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_ulong; +} +extern "C" { + #[doc = " Retrieve a directory object from the database for 'path'."] + #[doc = ""] + #[doc = " Here, 'path' should be a path relative to the path of 'database'"] + #[doc = " (see notmuch_database_get_path), or else should be an absolute path"] + #[doc = " with initial components that match the path of 'database'."] + #[doc = ""] + #[doc = " If this directory object does not exist in the database, this"] + #[doc = " returns NOTMUCH_STATUS_SUCCESS and sets *directory to NULL."] + #[doc = ""] + #[doc = " Otherwise the returned directory object is owned by the database"] + #[doc = " and as such, will only be valid until notmuch_database_destroy is"] + #[doc = " called."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: Successfully retrieved directory."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_NULL_POINTER: The given 'directory' argument is NULL."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred;"] + #[doc = "\tdirectory not retrieved."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_UPGRADE_REQUIRED: The caller must upgrade the"] + #[doc = " database to use this function."] + pub fn notmuch_database_get_directory( + database: *mut notmuch_database_t, + path: *const ::std::os::raw::c_char, + directory: *mut *mut notmuch_directory_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Add a message file to a database, indexing it for retrieval by"] + #[doc = " future searches. If a message already exists with the same message"] + #[doc = " ID as the specified file, their indexes will be merged, and this"] + #[doc = " new filename will also be associated with the existing message."] + #[doc = ""] + #[doc = " Here, 'filename' should be a path relative to the path of"] + #[doc = " 'database' (see notmuch_database_get_path), or else should be an"] + #[doc = " absolute filename with initial components that match the path of"] + #[doc = " 'database'."] + #[doc = ""] + #[doc = " The file should be a single mail message (not a multi-message mbox)"] + #[doc = " that is expected to remain at its current location, (since the"] + #[doc = " notmuch database will reference the filename, and will not copy the"] + #[doc = " entire contents of the file."] + #[doc = ""] + #[doc = " If another message with the same message ID already exists in the"] + #[doc = " database, rather than creating a new message, this adds the search"] + #[doc = " terms from the identified file to the existing message's index, and"] + #[doc = " adds 'filename' to the list of filenames known for the message."] + #[doc = ""] + #[doc = " The 'indexopts' parameter can be NULL (meaning, use the indexing"] + #[doc = " defaults from the database), or can be an explicit choice of"] + #[doc = " indexing options that should govern the indexing of this specific"] + #[doc = " 'filename'."] + #[doc = ""] + #[doc = " If 'message' is not NULL, then, on successful return"] + #[doc = " (NOTMUCH_STATUS_SUCCESS or NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) '*message'"] + #[doc = " will be initialized to a message object that can be used for things"] + #[doc = " such as adding tags to the just-added message. The user should call"] + #[doc = " notmuch_message_destroy when done with the message. On any failure"] + #[doc = " '*message' will be set to NULL."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: Message successfully added to database."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred,"] + #[doc = "\tmessage not added."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: Message has the same message"] + #[doc = "\tID as another message already in the database. The new"] + #[doc = "\tfilename was successfully added to the message in the database"] + #[doc = "\t(if not already present) and the existing message is returned."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_FILE_ERROR: an error occurred trying to open the"] + #[doc = "\tfile, (such as permission denied, or file not found,"] + #[doc = "\tetc.). Nothing added to the database."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_FILE_NOT_EMAIL: the contents of filename don't look"] + #[doc = "\tlike an email message. Nothing added to the database."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only"] + #[doc = "\tmode so no message can be added."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_UPGRADE_REQUIRED: The caller must upgrade the"] + #[doc = " database to use this function."] + #[doc = ""] + #[doc = " @since libnotmuch 5.1 (notmuch 0.26)"] + pub fn notmuch_database_index_file( + database: *mut notmuch_database_t, + filename: *const ::std::os::raw::c_char, + indexopts: *mut notmuch_indexopts_t, + message: *mut *mut notmuch_message_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Deprecated alias for notmuch_database_index_file called with"] + #[doc = " NULL indexopts."] + #[doc = ""] + #[doc = " @deprecated Deprecated as of libnotmuch 5.1 (notmuch 0.26). Please"] + #[doc = " use notmuch_database_index_file instead."] + #[doc = ""] + pub fn notmuch_database_add_message( + database: *mut notmuch_database_t, + filename: *const ::std::os::raw::c_char, + message: *mut *mut notmuch_message_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Remove a message filename from the given notmuch database. If the"] + #[doc = " message has no more filenames, remove the message."] + #[doc = ""] + #[doc = " If the same message (as determined by the message ID) is still"] + #[doc = " available via other filenames, then the message will persist in the"] + #[doc = " database for those filenames. When the last filename is removed for"] + #[doc = " a particular message, the database content for that message will be"] + #[doc = " entirely removed."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: The last filename was removed and the"] + #[doc = "\tmessage was removed from the database."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred,"] + #[doc = "\tmessage not removed."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: This filename was removed but"] + #[doc = "\tthe message persists in the database with at least one other"] + #[doc = "\tfilename."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only"] + #[doc = "\tmode so no message can be removed."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_UPGRADE_REQUIRED: The caller must upgrade the"] + #[doc = " database to use this function."] + pub fn notmuch_database_remove_message( + database: *mut notmuch_database_t, + filename: *const ::std::os::raw::c_char, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Find a message with the given message_id."] + #[doc = ""] + #[doc = " If a message with the given message_id is found then, on successful return"] + #[doc = " (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to a message"] + #[doc = " object. The caller should call notmuch_message_destroy when done with the"] + #[doc = " message."] + #[doc = ""] + #[doc = " On any failure or when the message is not found, this function initializes"] + #[doc = " '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the"] + #[doc = " caller is supposed to check '*message' for NULL to find out whether the"] + #[doc = " message with the given message_id was found."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating message object"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred"] + pub fn notmuch_database_find_message( + database: *mut notmuch_database_t, + message_id: *const ::std::os::raw::c_char, + message: *mut *mut notmuch_message_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Find a message with the given filename."] + #[doc = ""] + #[doc = " If the database contains a message with the given filename then, on"] + #[doc = " successful return (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to"] + #[doc = " a message object. The caller should call notmuch_message_destroy when done"] + #[doc = " with the message."] + #[doc = ""] + #[doc = " On any failure or when the message is not found, this function initializes"] + #[doc = " '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the"] + #[doc = " caller is supposed to check '*message' for NULL to find out whether the"] + #[doc = " message with the given filename is found."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating the message object"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_UPGRADE_REQUIRED: The caller must upgrade the"] + #[doc = " database to use this function."] + pub fn notmuch_database_find_message_by_filename( + notmuch: *mut notmuch_database_t, + filename: *const ::std::os::raw::c_char, + message: *mut *mut notmuch_message_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Return a list of all tags found in the database."] + #[doc = ""] + #[doc = " This function creates a list of all tags found in the database. The"] + #[doc = " resulting list contains all tags from all messages found in the database."] + #[doc = ""] + #[doc = " On error this function returns NULL."] + pub fn notmuch_database_get_all_tags(db: *mut notmuch_database_t) -> *mut notmuch_tags_t; +} +extern "C" { + #[doc = " Create a new query for 'database'."] + #[doc = ""] + #[doc = " Here, 'database' should be an open database, (see"] + #[doc = " notmuch_database_open and notmuch_database_create)."] + #[doc = ""] + #[doc = " For the query string, we'll document the syntax here more"] + #[doc = " completely in the future, but it's likely to be a specialized"] + #[doc = " version of the general Xapian query syntax:"] + #[doc = ""] + #[doc = " https://xapian.org/docs/queryparser.html"] + #[doc = ""] + #[doc = " As a special case, passing either a length-zero string, (that is \"\"),"] + #[doc = " or a string consisting of a single asterisk (that is \"*\"), will"] + #[doc = " result in a query that returns all messages in the database."] + #[doc = ""] + #[doc = " See notmuch_query_set_sort for controlling the order of results."] + #[doc = " See notmuch_query_search_messages and notmuch_query_search_threads"] + #[doc = " to actually execute the query."] + #[doc = ""] + #[doc = " User should call notmuch_query_destroy when finished with this"] + #[doc = " query."] + #[doc = ""] + #[doc = " Will return NULL if insufficient memory is available."] + pub fn notmuch_query_create( + database: *mut notmuch_database_t, + query_string: *const ::std::os::raw::c_char, + ) -> *mut notmuch_query_t; +} +#[doc = " Oldest first."] +pub const notmuch_sort_t_NOTMUCH_SORT_OLDEST_FIRST: notmuch_sort_t = 0; +#[doc = " Newest first."] +pub const notmuch_sort_t_NOTMUCH_SORT_NEWEST_FIRST: notmuch_sort_t = 1; +#[doc = " Sort by message-id."] +pub const notmuch_sort_t_NOTMUCH_SORT_MESSAGE_ID: notmuch_sort_t = 2; +#[doc = " Do not sort."] +pub const notmuch_sort_t_NOTMUCH_SORT_UNSORTED: notmuch_sort_t = 3; +#[doc = " Sort values for notmuch_query_set_sort."] +pub type notmuch_sort_t = u32; +extern "C" { + #[doc = " Return the query_string of this query. See notmuch_query_create."] + pub fn notmuch_query_get_query_string( + query: *const notmuch_query_t, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Return the notmuch database of this query. See notmuch_query_create."] + pub fn notmuch_query_get_database(query: *const notmuch_query_t) -> *mut notmuch_database_t; +} +pub const notmuch_exclude_t_NOTMUCH_EXCLUDE_FLAG: notmuch_exclude_t = 0; +pub const notmuch_exclude_t_NOTMUCH_EXCLUDE_TRUE: notmuch_exclude_t = 1; +pub const notmuch_exclude_t_NOTMUCH_EXCLUDE_FALSE: notmuch_exclude_t = 2; +pub const notmuch_exclude_t_NOTMUCH_EXCLUDE_ALL: notmuch_exclude_t = 3; +#[doc = " Exclude values for notmuch_query_set_omit_excluded. The strange"] +#[doc = " order is to maintain backward compatibility: the old FALSE/TRUE"] +#[doc = " options correspond to the new"] +#[doc = " NOTMUCH_EXCLUDE_FLAG/NOTMUCH_EXCLUDE_TRUE options."] +pub type notmuch_exclude_t = u32; +extern "C" { + #[doc = " Specify whether to omit excluded results or simply flag them. By"] + #[doc = " default, this is set to TRUE."] + #[doc = ""] + #[doc = " If set to TRUE or ALL, notmuch_query_search_messages will omit excluded"] + #[doc = " messages from the results, and notmuch_query_search_threads will omit"] + #[doc = " threads that match only in excluded messages. If set to TRUE,"] + #[doc = " notmuch_query_search_threads will include all messages in threads that"] + #[doc = " match in at least one non-excluded message. Otherwise, if set to ALL,"] + #[doc = " notmuch_query_search_threads will omit excluded messages from all threads."] + #[doc = ""] + #[doc = " If set to FALSE or FLAG then both notmuch_query_search_messages and"] + #[doc = " notmuch_query_search_threads will return all matching"] + #[doc = " messages/threads regardless of exclude status. If set to FLAG then"] + #[doc = " the exclude flag will be set for any excluded message that is"] + #[doc = " returned by notmuch_query_search_messages, and the thread counts"] + #[doc = " for threads returned by notmuch_query_search_threads will be the"] + #[doc = " number of non-excluded messages/matches. Otherwise, if set to"] + #[doc = " FALSE, then the exclude status is completely ignored."] + #[doc = ""] + #[doc = " The performance difference when calling"] + #[doc = " notmuch_query_search_messages should be relatively small (and both"] + #[doc = " should be very fast). However, in some cases,"] + #[doc = " notmuch_query_search_threads is very much faster when omitting"] + #[doc = " excluded messages as it does not need to construct the threads that"] + #[doc = " only match in excluded messages."] + pub fn notmuch_query_set_omit_excluded( + query: *mut notmuch_query_t, + omit_excluded: notmuch_exclude_t, + ); +} +extern "C" { + #[doc = " Specify the sorting desired for this query."] + pub fn notmuch_query_set_sort(query: *mut notmuch_query_t, sort: notmuch_sort_t); +} +extern "C" { + #[doc = " Return the sort specified for this query. See"] + #[doc = " notmuch_query_set_sort."] + pub fn notmuch_query_get_sort(query: *const notmuch_query_t) -> notmuch_sort_t; +} +extern "C" { + #[doc = " Add a tag that will be excluded from the query results by default."] + #[doc = " This exclusion will be ignored if this tag appears explicitly in"] + #[doc = " the query."] + #[doc = ""] + #[doc = " @returns"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: excluded was added successfully."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occurred."] + #[doc = " Most likely a problem lazily parsing the query string."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_IGNORED: tag is explicitly present in the query, so"] + #[doc = "\t\tnot excluded."] + pub fn notmuch_query_add_tag_exclude( + query: *mut notmuch_query_t, + tag: *const ::std::os::raw::c_char, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Execute a query for threads, returning a notmuch_threads_t object"] + #[doc = " which can be used to iterate over the results. The returned threads"] + #[doc = " object is owned by the query and as such, will only be valid until"] + #[doc = " notmuch_query_destroy."] + #[doc = ""] + #[doc = " Typical usage might be:"] + #[doc = ""] + #[doc = " notmuch_query_t *query;"] + #[doc = " notmuch_threads_t *threads;"] + #[doc = " notmuch_thread_t *thread;"] + #[doc = " notmuch_status_t stat;"] + #[doc = ""] + #[doc = " query = notmuch_query_create (database, query_string);"] + #[doc = ""] + #[doc = " for (stat = notmuch_query_search_threads (query, &threads);"] + #[doc = "\t stat == NOTMUCH_STATUS_SUCCESS &&"] + #[doc = " notmuch_threads_valid (threads);"] + #[doc = " notmuch_threads_move_to_next (threads))"] + #[doc = " {"] + #[doc = " thread = notmuch_threads_get (threads);"] + #[doc = " ...."] + #[doc = " notmuch_thread_destroy (thread);"] + #[doc = " }"] + #[doc = ""] + #[doc = " notmuch_query_destroy (query);"] + #[doc = ""] + #[doc = " Note: If you are finished with a thread before its containing"] + #[doc = " query, you can call notmuch_thread_destroy to clean up some memory"] + #[doc = " sooner (as in the above example). Otherwise, if your thread objects"] + #[doc = " are long-lived, then you don't need to call notmuch_thread_destroy"] + #[doc = " and all the memory will still be reclaimed when the query is"] + #[doc = " destroyed."] + #[doc = ""] + #[doc = " Note that there's no explicit destructor needed for the"] + #[doc = " notmuch_threads_t object. (For consistency, we do provide a"] + #[doc = " notmuch_threads_destroy function, but there's no good reason"] + #[doc = " to call it if the query is about to be destroyed)."] + #[doc = ""] + #[doc = " @since libnotmuch 5.0 (notmuch 0.25)"] + pub fn notmuch_query_search_threads( + query: *mut notmuch_query_t, + out: *mut *mut notmuch_threads_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Deprecated alias for notmuch_query_search_threads."] + #[doc = ""] + #[doc = " @deprecated Deprecated as of libnotmuch 5 (notmuch 0.25). Please"] + #[doc = " use notmuch_query_search_threads instead."] + #[doc = ""] + pub fn notmuch_query_search_threads_st( + query: *mut notmuch_query_t, + out: *mut *mut notmuch_threads_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Execute a query for messages, returning a notmuch_messages_t object"] + #[doc = " which can be used to iterate over the results. The returned"] + #[doc = " messages object is owned by the query and as such, will only be"] + #[doc = " valid until notmuch_query_destroy."] + #[doc = ""] + #[doc = " Typical usage might be:"] + #[doc = ""] + #[doc = " notmuch_query_t *query;"] + #[doc = " notmuch_messages_t *messages;"] + #[doc = " notmuch_message_t *message;"] + #[doc = ""] + #[doc = " query = notmuch_query_create (database, query_string);"] + #[doc = ""] + #[doc = " for (messages = notmuch_query_search_messages (query);"] + #[doc = " notmuch_messages_valid (messages);"] + #[doc = " notmuch_messages_move_to_next (messages))"] + #[doc = " {"] + #[doc = " message = notmuch_messages_get (messages);"] + #[doc = " ...."] + #[doc = " notmuch_message_destroy (message);"] + #[doc = " }"] + #[doc = ""] + #[doc = " notmuch_query_destroy (query);"] + #[doc = ""] + #[doc = " Note: If you are finished with a message before its containing"] + #[doc = " query, you can call notmuch_message_destroy to clean up some memory"] + #[doc = " sooner (as in the above example). Otherwise, if your message"] + #[doc = " objects are long-lived, then you don't need to call"] + #[doc = " notmuch_message_destroy and all the memory will still be reclaimed"] + #[doc = " when the query is destroyed."] + #[doc = ""] + #[doc = " Note that there's no explicit destructor needed for the"] + #[doc = " notmuch_messages_t object. (For consistency, we do provide a"] + #[doc = " notmuch_messages_destroy function, but there's no good"] + #[doc = " reason to call it if the query is about to be destroyed)."] + #[doc = ""] + #[doc = " If a Xapian exception occurs this function will return NULL."] + #[doc = ""] + #[doc = " @since libnotmuch 5 (notmuch 0.25)"] + pub fn notmuch_query_search_messages( + query: *mut notmuch_query_t, + out: *mut *mut notmuch_messages_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Deprecated alias for notmuch_query_search_messages"] + #[doc = ""] + #[doc = " @deprecated Deprecated as of libnotmuch 5 (notmuch 0.25). Please use"] + #[doc = " notmuch_query_search_messages instead."] + #[doc = ""] + pub fn notmuch_query_search_messages_st( + query: *mut notmuch_query_t, + out: *mut *mut notmuch_messages_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Destroy a notmuch_query_t along with any associated resources."] + #[doc = ""] + #[doc = " This will in turn destroy any notmuch_threads_t and"] + #[doc = " notmuch_messages_t objects generated by this query, (and in"] + #[doc = " turn any notmuch_thread_t and notmuch_message_t objects generated"] + #[doc = " from those results, etc.), if such objects haven't already been"] + #[doc = " destroyed."] + pub fn notmuch_query_destroy(query: *mut notmuch_query_t); +} +extern "C" { + #[doc = " Is the given 'threads' iterator pointing at a valid thread."] + #[doc = ""] + #[doc = " When this function returns TRUE, notmuch_threads_get will return a"] + #[doc = " valid object. Whereas when this function returns FALSE,"] + #[doc = " notmuch_threads_get will return NULL."] + #[doc = ""] + #[doc = " If passed a NULL pointer, this function returns FALSE"] + #[doc = ""] + #[doc = " See the documentation of notmuch_query_search_threads for example"] + #[doc = " code showing how to iterate over a notmuch_threads_t object."] + pub fn notmuch_threads_valid(threads: *mut notmuch_threads_t) -> notmuch_bool_t; +} +extern "C" { + #[doc = " Get the current thread from 'threads' as a notmuch_thread_t."] + #[doc = ""] + #[doc = " Note: The returned thread belongs to 'threads' and has a lifetime"] + #[doc = " identical to it (and the query to which it belongs)."] + #[doc = ""] + #[doc = " See the documentation of notmuch_query_search_threads for example"] + #[doc = " code showing how to iterate over a notmuch_threads_t object."] + #[doc = ""] + #[doc = " If an out-of-memory situation occurs, this function will return"] + #[doc = " NULL."] + pub fn notmuch_threads_get(threads: *mut notmuch_threads_t) -> *mut notmuch_thread_t; +} +extern "C" { + #[doc = " Move the 'threads' iterator to the next thread."] + #[doc = ""] + #[doc = " If 'threads' is already pointing at the last thread then the"] + #[doc = " iterator will be moved to a point just beyond that last thread,"] + #[doc = " (where notmuch_threads_valid will return FALSE and"] + #[doc = " notmuch_threads_get will return NULL)."] + #[doc = ""] + #[doc = " See the documentation of notmuch_query_search_threads for example"] + #[doc = " code showing how to iterate over a notmuch_threads_t object."] + pub fn notmuch_threads_move_to_next(threads: *mut notmuch_threads_t); +} +extern "C" { + #[doc = " Destroy a notmuch_threads_t object."] + #[doc = ""] + #[doc = " It's not strictly necessary to call this function. All memory from"] + #[doc = " the notmuch_threads_t object will be reclaimed when the"] + #[doc = " containing query object is destroyed."] + pub fn notmuch_threads_destroy(threads: *mut notmuch_threads_t); +} +extern "C" { + #[doc = " Return the number of messages matching a search."] + #[doc = ""] + #[doc = " This function performs a search and returns the number of matching"] + #[doc = " messages."] + #[doc = ""] + #[doc = " @returns"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: query completed successfully."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occurred. The"] + #[doc = " value of *count is not defined."] + #[doc = ""] + #[doc = " @since libnotmuch 5 (notmuch 0.25)"] + pub fn notmuch_query_count_messages( + query: *mut notmuch_query_t, + count: *mut ::std::os::raw::c_uint, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Deprecated alias for notmuch_query_count_messages"] + #[doc = ""] + #[doc = ""] + #[doc = " @deprecated Deprecated since libnotmuch 5.0 (notmuch 0.25). Please"] + #[doc = " use notmuch_query_count_messages instead."] + pub fn notmuch_query_count_messages_st( + query: *mut notmuch_query_t, + count: *mut ::std::os::raw::c_uint, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Return the number of threads matching a search."] + #[doc = ""] + #[doc = " This function performs a search and returns the number of unique thread IDs"] + #[doc = " in the matching messages. This is the same as number of threads matching a"] + #[doc = " search."] + #[doc = ""] + #[doc = " Note that this is a significantly heavier operation than"] + #[doc = " notmuch_query_count_messages{_st}()."] + #[doc = ""] + #[doc = " @returns"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_OUT_OF_MEMORY: Memory allocation failed. The value"] + #[doc = " of *count is not defined"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: query completed successfully."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occurred. The"] + #[doc = " value of *count is not defined."] + #[doc = ""] + #[doc = " @since libnotmuch 5 (notmuch 0.25)"] + pub fn notmuch_query_count_threads( + query: *mut notmuch_query_t, + count: *mut ::std::os::raw::c_uint, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Deprecated alias for notmuch_query_count_threads"] + #[doc = ""] + #[doc = " @deprecated Deprecated as of libnotmuch 5.0 (notmuch 0.25). Please"] + #[doc = " use notmuch_query_count_threads_st instead."] + pub fn notmuch_query_count_threads_st( + query: *mut notmuch_query_t, + count: *mut ::std::os::raw::c_uint, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Get the thread ID of 'thread'."] + #[doc = ""] + #[doc = " The returned string belongs to 'thread' and as such, should not be"] + #[doc = " modified by the caller and will only be valid for as long as the"] + #[doc = " thread is valid, (which is until notmuch_thread_destroy or until"] + #[doc = " the query from which it derived is destroyed)."] + pub fn notmuch_thread_get_thread_id( + thread: *mut notmuch_thread_t, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Get the total number of messages in 'thread'."] + #[doc = ""] + #[doc = " This count consists of all messages in the database belonging to"] + #[doc = " this thread. Contrast with notmuch_thread_get_matched_messages() ."] + pub fn notmuch_thread_get_total_messages( + thread: *mut notmuch_thread_t, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Get the total number of files in 'thread'."] + #[doc = ""] + #[doc = " This sums notmuch_message_count_files over all messages in the"] + #[doc = " thread"] + #[doc = " @returns Non-negative integer"] + #[doc = " @since libnotmuch 5.0 (notmuch 0.25)"] + pub fn notmuch_thread_get_total_files(thread: *mut notmuch_thread_t) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Get a notmuch_messages_t iterator for the top-level messages in"] + #[doc = " 'thread' in oldest-first order."] + #[doc = ""] + #[doc = " This iterator will not necessarily iterate over all of the messages"] + #[doc = " in the thread. It will only iterate over the messages in the thread"] + #[doc = " which are not replies to other messages in the thread."] + #[doc = ""] + #[doc = " The returned list will be destroyed when the thread is destroyed."] + pub fn notmuch_thread_get_toplevel_messages( + thread: *mut notmuch_thread_t, + ) -> *mut notmuch_messages_t; +} +extern "C" { + #[doc = " Get a notmuch_thread_t iterator for all messages in 'thread' in"] + #[doc = " oldest-first order."] + #[doc = ""] + #[doc = " The returned list will be destroyed when the thread is destroyed."] + pub fn notmuch_thread_get_messages(thread: *mut notmuch_thread_t) -> *mut notmuch_messages_t; +} +extern "C" { + #[doc = " Get the number of messages in 'thread' that matched the search."] + #[doc = ""] + #[doc = " This count includes only the messages in this thread that were"] + #[doc = " matched by the search from which the thread was created and were"] + #[doc = " not excluded by any exclude tags passed in with the query (see"] + #[doc = " notmuch_query_add_tag_exclude). Contrast with"] + #[doc = " notmuch_thread_get_total_messages() ."] + pub fn notmuch_thread_get_matched_messages( + thread: *mut notmuch_thread_t, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Get the authors of 'thread' as a UTF-8 string."] + #[doc = ""] + #[doc = " The returned string is a comma-separated list of the names of the"] + #[doc = " authors of mail messages in the query results that belong to this"] + #[doc = " thread."] + #[doc = ""] + #[doc = " The string contains authors of messages matching the query first, then"] + #[doc = " non-matched authors (with the two groups separated by '|'). Within"] + #[doc = " each group, authors are ordered by date."] + #[doc = ""] + #[doc = " The returned string belongs to 'thread' and as such, should not be"] + #[doc = " modified by the caller and will only be valid for as long as the"] + #[doc = " thread is valid, (which is until notmuch_thread_destroy or until"] + #[doc = " the query from which it derived is destroyed)."] + pub fn notmuch_thread_get_authors( + thread: *mut notmuch_thread_t, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Get the subject of 'thread' as a UTF-8 string."] + #[doc = ""] + #[doc = " The subject is taken from the first message (according to the query"] + #[doc = " order---see notmuch_query_set_sort) in the query results that"] + #[doc = " belongs to this thread."] + #[doc = ""] + #[doc = " The returned string belongs to 'thread' and as such, should not be"] + #[doc = " modified by the caller and will only be valid for as long as the"] + #[doc = " thread is valid, (which is until notmuch_thread_destroy or until"] + #[doc = " the query from which it derived is destroyed)."] + pub fn notmuch_thread_get_subject( + thread: *mut notmuch_thread_t, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Get the date of the oldest message in 'thread' as a time_t value."] + pub fn notmuch_thread_get_oldest_date(thread: *mut notmuch_thread_t) -> time_t; +} +extern "C" { + #[doc = " Get the date of the newest message in 'thread' as a time_t value."] + pub fn notmuch_thread_get_newest_date(thread: *mut notmuch_thread_t) -> time_t; +} +extern "C" { + #[doc = " Get the tags for 'thread', returning a notmuch_tags_t object which"] + #[doc = " can be used to iterate over all tags."] + #[doc = ""] + #[doc = " Note: In the Notmuch database, tags are stored on individual"] + #[doc = " messages, not on threads. So the tags returned here will be all"] + #[doc = " tags of the messages which matched the search and which belong to"] + #[doc = " this thread."] + #[doc = ""] + #[doc = " The tags object is owned by the thread and as such, will only be"] + #[doc = " valid for as long as the thread is valid, (for example, until"] + #[doc = " notmuch_thread_destroy or until the query from which it derived is"] + #[doc = " destroyed)."] + #[doc = ""] + #[doc = " Typical usage might be:"] + #[doc = ""] + #[doc = " notmuch_thread_t *thread;"] + #[doc = " notmuch_tags_t *tags;"] + #[doc = " const char *tag;"] + #[doc = ""] + #[doc = " thread = notmuch_threads_get (threads);"] + #[doc = ""] + #[doc = " for (tags = notmuch_thread_get_tags (thread);"] + #[doc = " notmuch_tags_valid (tags);"] + #[doc = " notmuch_tags_move_to_next (tags))"] + #[doc = " {"] + #[doc = " tag = notmuch_tags_get (tags);"] + #[doc = " ...."] + #[doc = " }"] + #[doc = ""] + #[doc = " notmuch_thread_destroy (thread);"] + #[doc = ""] + #[doc = " Note that there's no explicit destructor needed for the"] + #[doc = " notmuch_tags_t object. (For consistency, we do provide a"] + #[doc = " notmuch_tags_destroy function, but there's no good reason to call"] + #[doc = " it if the message is about to be destroyed)."] + pub fn notmuch_thread_get_tags(thread: *mut notmuch_thread_t) -> *mut notmuch_tags_t; +} +extern "C" { + #[doc = " Destroy a notmuch_thread_t object."] + pub fn notmuch_thread_destroy(thread: *mut notmuch_thread_t); +} +extern "C" { + #[doc = " Is the given 'messages' iterator pointing at a valid message."] + #[doc = ""] + #[doc = " When this function returns TRUE, notmuch_messages_get will return a"] + #[doc = " valid object. Whereas when this function returns FALSE,"] + #[doc = " notmuch_messages_get will return NULL."] + #[doc = ""] + #[doc = " See the documentation of notmuch_query_search_messages for example"] + #[doc = " code showing how to iterate over a notmuch_messages_t object."] + pub fn notmuch_messages_valid(messages: *mut notmuch_messages_t) -> notmuch_bool_t; +} +extern "C" { + #[doc = " Get the current message from 'messages' as a notmuch_message_t."] + #[doc = ""] + #[doc = " Note: The returned message belongs to 'messages' and has a lifetime"] + #[doc = " identical to it (and the query to which it belongs)."] + #[doc = ""] + #[doc = " See the documentation of notmuch_query_search_messages for example"] + #[doc = " code showing how to iterate over a notmuch_messages_t object."] + #[doc = ""] + #[doc = " If an out-of-memory situation occurs, this function will return"] + #[doc = " NULL."] + pub fn notmuch_messages_get(messages: *mut notmuch_messages_t) -> *mut notmuch_message_t; +} +extern "C" { + #[doc = " Move the 'messages' iterator to the next message."] + #[doc = ""] + #[doc = " If 'messages' is already pointing at the last message then the"] + #[doc = " iterator will be moved to a point just beyond that last message,"] + #[doc = " (where notmuch_messages_valid will return FALSE and"] + #[doc = " notmuch_messages_get will return NULL)."] + #[doc = ""] + #[doc = " See the documentation of notmuch_query_search_messages for example"] + #[doc = " code showing how to iterate over a notmuch_messages_t object."] + pub fn notmuch_messages_move_to_next(messages: *mut notmuch_messages_t); +} +extern "C" { + #[doc = " Destroy a notmuch_messages_t object."] + #[doc = ""] + #[doc = " It's not strictly necessary to call this function. All memory from"] + #[doc = " the notmuch_messages_t object will be reclaimed when the containing"] + #[doc = " query object is destroyed."] + pub fn notmuch_messages_destroy(messages: *mut notmuch_messages_t); +} +extern "C" { + #[doc = " Return a list of tags from all messages."] + #[doc = ""] + #[doc = " The resulting list is guaranteed not to contain duplicated tags."] + #[doc = ""] + #[doc = " WARNING: You can no longer iterate over messages after calling this"] + #[doc = " function, because the iterator will point at the end of the list."] + #[doc = " We do not have a function to reset the iterator yet and the only"] + #[doc = " way how you can iterate over the list again is to recreate the"] + #[doc = " message list."] + #[doc = ""] + #[doc = " The function returns NULL on error."] + pub fn notmuch_messages_collect_tags(messages: *mut notmuch_messages_t) -> *mut notmuch_tags_t; +} +extern "C" { + #[doc = " Get the database associated with this message."] + #[doc = ""] + #[doc = " @since libnotmuch 5.2 (notmuch 0.27)"] + pub fn notmuch_message_get_database( + message: *const notmuch_message_t, + ) -> *mut notmuch_database_t; +} +extern "C" { + #[doc = " Get the message ID of 'message'."] + #[doc = ""] + #[doc = " The returned string belongs to 'message' and as such, should not be"] + #[doc = " modified by the caller and will only be valid for as long as the"] + #[doc = " message is valid, (which is until the query from which it derived"] + #[doc = " is destroyed)."] + #[doc = ""] + #[doc = " This function will not return NULL since Notmuch ensures that every"] + #[doc = " message has a unique message ID, (Notmuch will generate an ID for a"] + #[doc = " message if the original file does not contain one)."] + pub fn notmuch_message_get_message_id( + message: *mut notmuch_message_t, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Get the thread ID of 'message'."] + #[doc = ""] + #[doc = " The returned string belongs to 'message' and as such, should not be"] + #[doc = " modified by the caller and will only be valid for as long as the"] + #[doc = " message is valid, (for example, until the user calls"] + #[doc = " notmuch_message_destroy on 'message' or until a query from which it"] + #[doc = " derived is destroyed)."] + #[doc = ""] + #[doc = " This function will not return NULL since Notmuch ensures that every"] + #[doc = " message belongs to a single thread."] + pub fn notmuch_message_get_thread_id( + message: *mut notmuch_message_t, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Get a notmuch_messages_t iterator for all of the replies to"] + #[doc = " 'message'."] + #[doc = ""] + #[doc = " Note: This call only makes sense if 'message' was ultimately"] + #[doc = " obtained from a notmuch_thread_t object, (such as by coming"] + #[doc = " directly from the result of calling notmuch_thread_get_"] + #[doc = " toplevel_messages or by any number of subsequent"] + #[doc = " calls to notmuch_message_get_replies)."] + #[doc = ""] + #[doc = " If 'message' was obtained through some non-thread means, (such as"] + #[doc = " by a call to notmuch_query_search_messages), then this function"] + #[doc = " will return NULL."] + #[doc = ""] + #[doc = " If there are no replies to 'message', this function will return"] + #[doc = " NULL. (Note that notmuch_messages_valid will accept that NULL"] + #[doc = " value as legitimate, and simply return FALSE for it.)"] + #[doc = ""] + #[doc = " The returned list will be destroyed when the thread is destroyed."] + pub fn notmuch_message_get_replies(message: *mut notmuch_message_t) -> *mut notmuch_messages_t; +} +extern "C" { + #[doc = " Get the total number of files associated with a message."] + #[doc = " @returns Non-negative integer"] + #[doc = " @since libnotmuch 5.0 (notmuch 0.25)"] + pub fn notmuch_message_count_files(message: *mut notmuch_message_t) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Get a filename for the email corresponding to 'message'."] + #[doc = ""] + #[doc = " The returned filename is an absolute filename, (the initial"] + #[doc = " component will match notmuch_database_get_path() )."] + #[doc = ""] + #[doc = " The returned string belongs to the message so should not be"] + #[doc = " modified or freed by the caller (nor should it be referenced after"] + #[doc = " the message is destroyed)."] + #[doc = ""] + #[doc = " Note: If this message corresponds to multiple files in the mail"] + #[doc = " store, (that is, multiple files contain identical message IDs),"] + #[doc = " this function will arbitrarily return a single one of those"] + #[doc = " filenames. See notmuch_message_get_filenames for returning the"] + #[doc = " complete list of filenames."] + pub fn notmuch_message_get_filename( + message: *mut notmuch_message_t, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Get all filenames for the email corresponding to 'message'."] + #[doc = ""] + #[doc = " Returns a notmuch_filenames_t iterator listing all the filenames"] + #[doc = " associated with 'message'. These files may not have identical"] + #[doc = " content, but each will have the identical Message-ID."] + #[doc = ""] + #[doc = " Each filename in the iterator is an absolute filename, (the initial"] + #[doc = " component will match notmuch_database_get_path() )."] + pub fn notmuch_message_get_filenames( + message: *mut notmuch_message_t, + ) -> *mut notmuch_filenames_t; +} +extern "C" { + #[doc = " Re-index the e-mail corresponding to 'message' using the supplied index options"] + #[doc = ""] + #[doc = " Returns the status of the re-index operation. (see the return"] + #[doc = " codes documented in notmuch_database_index_file)"] + #[doc = ""] + #[doc = " After reindexing, the user should discard the message object passed"] + #[doc = " in here by calling notmuch_message_destroy, since it refers to the"] + #[doc = " original message, not to the reindexed message."] + pub fn notmuch_message_reindex( + message: *mut notmuch_message_t, + indexopts: *mut notmuch_indexopts_t, + ) -> notmuch_status_t; +} +pub const _notmuch_message_flag_NOTMUCH_MESSAGE_FLAG_MATCH: _notmuch_message_flag = 0; +pub const _notmuch_message_flag_NOTMUCH_MESSAGE_FLAG_EXCLUDED: _notmuch_message_flag = 1; +pub const _notmuch_message_flag_NOTMUCH_MESSAGE_FLAG_GHOST: _notmuch_message_flag = 2; +#[doc = " Message flags."] +pub type _notmuch_message_flag = u32; +pub use self::_notmuch_message_flag as notmuch_message_flag_t; +extern "C" { + #[doc = " Get a value of a flag for the email corresponding to 'message'."] + pub fn notmuch_message_get_flag( + message: *mut notmuch_message_t, + flag: notmuch_message_flag_t, + ) -> notmuch_bool_t; +} +extern "C" { + #[doc = " Set a value of a flag for the email corresponding to 'message'."] + pub fn notmuch_message_set_flag( + message: *mut notmuch_message_t, + flag: notmuch_message_flag_t, + value: notmuch_bool_t, + ); +} +extern "C" { + #[doc = " Get the date of 'message' as a time_t value."] + #[doc = ""] + #[doc = " For the original textual representation of the Date header from the"] + #[doc = " message call notmuch_message_get_header() with a header value of"] + #[doc = " \"date\"."] + pub fn notmuch_message_get_date(message: *mut notmuch_message_t) -> time_t; +} +extern "C" { + #[doc = " Get the value of the specified header from 'message' as a UTF-8 string."] + #[doc = ""] + #[doc = " Common headers are stored in the database when the message is"] + #[doc = " indexed and will be returned from the database. Other headers will"] + #[doc = " be read from the actual message file."] + #[doc = ""] + #[doc = " The header name is case insensitive."] + #[doc = ""] + #[doc = " The returned string belongs to the message so should not be"] + #[doc = " modified or freed by the caller (nor should it be referenced after"] + #[doc = " the message is destroyed)."] + #[doc = ""] + #[doc = " Returns an empty string (\"\") if the message does not contain a"] + #[doc = " header line matching 'header'. Returns NULL if any error occurs."] + pub fn notmuch_message_get_header( + message: *mut notmuch_message_t, + header: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Get the tags for 'message', returning a notmuch_tags_t object which"] + #[doc = " can be used to iterate over all tags."] + #[doc = ""] + #[doc = " The tags object is owned by the message and as such, will only be"] + #[doc = " valid for as long as the message is valid, (which is until the"] + #[doc = " query from which it derived is destroyed)."] + #[doc = ""] + #[doc = " Typical usage might be:"] + #[doc = ""] + #[doc = " notmuch_message_t *message;"] + #[doc = " notmuch_tags_t *tags;"] + #[doc = " const char *tag;"] + #[doc = ""] + #[doc = " message = notmuch_database_find_message (database, message_id);"] + #[doc = ""] + #[doc = " for (tags = notmuch_message_get_tags (message);"] + #[doc = " notmuch_tags_valid (tags);"] + #[doc = " notmuch_tags_move_to_next (tags))"] + #[doc = " {"] + #[doc = " tag = notmuch_tags_get (tags);"] + #[doc = " ...."] + #[doc = " }"] + #[doc = ""] + #[doc = " notmuch_message_destroy (message);"] + #[doc = ""] + #[doc = " Note that there's no explicit destructor needed for the"] + #[doc = " notmuch_tags_t object. (For consistency, we do provide a"] + #[doc = " notmuch_tags_destroy function, but there's no good reason to call"] + #[doc = " it if the message is about to be destroyed)."] + pub fn notmuch_message_get_tags(message: *mut notmuch_message_t) -> *mut notmuch_tags_t; +} +extern "C" { + #[doc = " Add a tag to the given message."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: Tag successfully added to message"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_NULL_POINTER: The 'tag' argument is NULL"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long"] + #[doc = "\t(exceeds NOTMUCH_TAG_MAX)"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only"] + #[doc = "\tmode so message cannot be modified."] + pub fn notmuch_message_add_tag( + message: *mut notmuch_message_t, + tag: *const ::std::os::raw::c_char, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Remove a tag from the given message."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: Tag successfully removed from message"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_NULL_POINTER: The 'tag' argument is NULL"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long"] + #[doc = "\t(exceeds NOTMUCH_TAG_MAX)"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only"] + #[doc = "\tmode so message cannot be modified."] + pub fn notmuch_message_remove_tag( + message: *mut notmuch_message_t, + tag: *const ::std::os::raw::c_char, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Remove all tags from the given message."] + #[doc = ""] + #[doc = " See notmuch_message_freeze for an example showing how to safely"] + #[doc = " replace tag values."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only"] + #[doc = "\tmode so message cannot be modified."] + pub fn notmuch_message_remove_all_tags(message: *mut notmuch_message_t) -> notmuch_status_t; +} +extern "C" { + #[doc = " Add/remove tags according to maildir flags in the message filename(s)."] + #[doc = ""] + #[doc = " This function examines the filenames of 'message' for maildir"] + #[doc = " flags, and adds or removes tags on 'message' as follows when these"] + #[doc = " flags are present:"] + #[doc = ""] + #[doc = "\tFlag\tAction if present"] + #[doc = "\t----\t-----------------"] + #[doc = "\t'D'\tAdds the \"draft\" tag to the message"] + #[doc = "\t'F'\tAdds the \"flagged\" tag to the message"] + #[doc = "\t'P'\tAdds the \"passed\" tag to the message"] + #[doc = "\t'R'\tAdds the \"replied\" tag to the message"] + #[doc = "\t'S'\tRemoves the \"unread\" tag from the message"] + #[doc = ""] + #[doc = " For each flag that is not present, the opposite action (add/remove)"] + #[doc = " is performed for the corresponding tags."] + #[doc = ""] + #[doc = " Flags are identified as trailing components of the filename after a"] + #[doc = " sequence of \":2,\"."] + #[doc = ""] + #[doc = " If there are multiple filenames associated with this message, the"] + #[doc = " flag is considered present if it appears in one or more"] + #[doc = " filenames. (That is, the flags from the multiple filenames are"] + #[doc = " combined with the logical OR operator.)"] + #[doc = ""] + #[doc = " A client can ensure that notmuch database tags remain synchronized"] + #[doc = " with maildir flags by calling this function after each call to"] + #[doc = " notmuch_database_index_file. See also"] + #[doc = " notmuch_message_tags_to_maildir_flags for synchronizing tag changes"] + #[doc = " back to maildir flags."] + pub fn notmuch_message_maildir_flags_to_tags( + message: *mut notmuch_message_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " return TRUE if any filename of 'message' has maildir flag 'flag',"] + #[doc = " FALSE otherwise."] + #[doc = ""] + pub fn notmuch_message_has_maildir_flag( + message: *mut notmuch_message_t, + flag: ::std::os::raw::c_char, + ) -> notmuch_bool_t; +} +extern "C" { + #[doc = " Rename message filename(s) to encode tags as maildir flags."] + #[doc = ""] + #[doc = " Specifically, for each filename corresponding to this message:"] + #[doc = ""] + #[doc = " If the filename is not in a maildir directory, do nothing. (A"] + #[doc = " maildir directory is determined as a directory named \"new\" or"] + #[doc = " \"cur\".) Similarly, if the filename has invalid maildir info,"] + #[doc = " (repeated or outof-ASCII-order flag characters after \":2,\"), then"] + #[doc = " do nothing."] + #[doc = ""] + #[doc = " If the filename is in a maildir directory, rename the file so that"] + #[doc = " its filename ends with the sequence \":2,\" followed by zero or more"] + #[doc = " of the following single-character flags (in ASCII order):"] + #[doc = ""] + #[doc = " * flag 'D' iff the message has the \"draft\" tag"] + #[doc = " * flag 'F' iff the message has the \"flagged\" tag"] + #[doc = " * flag 'P' iff the message has the \"passed\" tag"] + #[doc = " * flag 'R' iff the message has the \"replied\" tag"] + #[doc = " * flag 'S' iff the message does not have the \"unread\" tag"] + #[doc = ""] + #[doc = " Any existing flags unmentioned in the list above will be preserved"] + #[doc = " in the renaming."] + #[doc = ""] + #[doc = " Also, if this filename is in a directory named \"new\", rename it to"] + #[doc = " be within the neighboring directory named \"cur\"."] + #[doc = ""] + #[doc = " A client can ensure that maildir filename flags remain synchronized"] + #[doc = " with notmuch database tags by calling this function after changing"] + #[doc = " tags, (after calls to notmuch_message_add_tag,"] + #[doc = " notmuch_message_remove_tag, or notmuch_message_freeze/"] + #[doc = " notmuch_message_thaw). See also notmuch_message_maildir_flags_to_tags"] + #[doc = " for synchronizing maildir flag changes back to tags."] + pub fn notmuch_message_tags_to_maildir_flags( + message: *mut notmuch_message_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Freeze the current state of 'message' within the database."] + #[doc = ""] + #[doc = " This means that changes to the message state, (via"] + #[doc = " notmuch_message_add_tag, notmuch_message_remove_tag, and"] + #[doc = " notmuch_message_remove_all_tags), will not be committed to the"] + #[doc = " database until the message is thawed with notmuch_message_thaw."] + #[doc = ""] + #[doc = " Multiple calls to freeze/thaw are valid and these calls will"] + #[doc = " \"stack\". That is there must be as many calls to thaw as to freeze"] + #[doc = " before a message is actually thawed."] + #[doc = ""] + #[doc = " The ability to do freeze/thaw allows for safe transactions to"] + #[doc = " change tag values. For example, explicitly setting a message to"] + #[doc = " have a given set of tags might look like this:"] + #[doc = ""] + #[doc = " notmuch_message_freeze (message);"] + #[doc = ""] + #[doc = " notmuch_message_remove_all_tags (message);"] + #[doc = ""] + #[doc = " for (i = 0; i < NUM_TAGS; i++)"] + #[doc = " notmuch_message_add_tag (message, tags[i]);"] + #[doc = ""] + #[doc = " notmuch_message_thaw (message);"] + #[doc = ""] + #[doc = " With freeze/thaw used like this, the message in the database is"] + #[doc = " guaranteed to have either the full set of original tag values, or"] + #[doc = " the full set of new tag values, but nothing in between."] + #[doc = ""] + #[doc = " Imagine the example above without freeze/thaw and the operation"] + #[doc = " somehow getting interrupted. This could result in the message being"] + #[doc = " left with no tags if the interruption happened after"] + #[doc = " notmuch_message_remove_all_tags but before notmuch_message_add_tag."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: Message successfully frozen."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only"] + #[doc = "\tmode so message cannot be modified."] + pub fn notmuch_message_freeze(message: *mut notmuch_message_t) -> notmuch_status_t; +} +extern "C" { + #[doc = " Thaw the current 'message', synchronizing any changes that may have"] + #[doc = " occurred while 'message' was frozen into the notmuch database."] + #[doc = ""] + #[doc = " See notmuch_message_freeze for an example of how to use this"] + #[doc = " function to safely provide tag changes."] + #[doc = ""] + #[doc = " Multiple calls to freeze/thaw are valid and these calls with"] + #[doc = " \"stack\". That is there must be as many calls to thaw as to freeze"] + #[doc = " before a message is actually thawed."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: Message successfully thawed, (or at least"] + #[doc = "\tits frozen count has successfully been reduced by 1)."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: An attempt was made to thaw"] + #[doc = "\tan unfrozen message. That is, there have been an unbalanced"] + #[doc = "\tnumber of calls to notmuch_message_freeze and"] + #[doc = "\tnotmuch_message_thaw."] + pub fn notmuch_message_thaw(message: *mut notmuch_message_t) -> notmuch_status_t; +} +extern "C" { + #[doc = " Destroy a notmuch_message_t object."] + #[doc = ""] + #[doc = " It can be useful to call this function in the case of a single"] + #[doc = " query object with many messages in the result, (such as iterating"] + #[doc = " over the entire database). Otherwise, it's fine to never call this"] + #[doc = " function and there will still be no memory leaks. (The memory from"] + #[doc = " the messages get reclaimed when the containing query is destroyed.)"] + pub fn notmuch_message_destroy(message: *mut notmuch_message_t); +} +extern "C" { + #[doc = " @name Message Properties"] + #[doc = ""] + #[doc = " This interface provides the ability to attach arbitrary (key,value)"] + #[doc = " string pairs to a message, to remove such pairs, and to iterate"] + #[doc = " over them. The caller should take some care as to what keys they"] + #[doc = " add or delete values for, as other subsystems or extensions may"] + #[doc = " depend on these properties."] + #[doc = ""] + #[doc = " Please see notmuch-properties(7) for more details about specific"] + #[doc = " properties and conventions around their use."] + #[doc = ""] + #[doc = " Retrieve the value for a single property key"] + #[doc = ""] + #[doc = " *value* is set to a string owned by the message or NULL if there is"] + #[doc = " no such key. In the case of multiple values for the given key, the"] + #[doc = " first one is retrieved."] + #[doc = ""] + #[doc = " @returns"] + #[doc = " - NOTMUCH_STATUS_NULL_POINTER: *value* may not be NULL."] + #[doc = " - NOTMUCH_STATUS_SUCCESS: No error occurred."] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_message_get_property( + message: *mut notmuch_message_t, + key: *const ::std::os::raw::c_char, + value: *mut *const ::std::os::raw::c_char, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Add a (key,value) pair to a message"] + #[doc = ""] + #[doc = " @returns"] + #[doc = " - NOTMUCH_STATUS_ILLEGAL_ARGUMENT: *key* may not contain an '=' character."] + #[doc = " - NOTMUCH_STATUS_NULL_POINTER: Neither *key* nor *value* may be NULL."] + #[doc = " - NOTMUCH_STATUS_SUCCESS: No error occurred."] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_message_add_property( + message: *mut notmuch_message_t, + key: *const ::std::os::raw::c_char, + value: *const ::std::os::raw::c_char, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Remove a (key,value) pair from a message."] + #[doc = ""] + #[doc = " It is not an error to remove a non-existant (key,value) pair"] + #[doc = ""] + #[doc = " @returns"] + #[doc = " - NOTMUCH_STATUS_ILLEGAL_ARGUMENT: *key* may not contain an '=' character."] + #[doc = " - NOTMUCH_STATUS_NULL_POINTER: Neither *key* nor *value* may be NULL."] + #[doc = " - NOTMUCH_STATUS_SUCCESS: No error occurred."] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_message_remove_property( + message: *mut notmuch_message_t, + key: *const ::std::os::raw::c_char, + value: *const ::std::os::raw::c_char, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Remove all (key,value) pairs from the given message."] + #[doc = ""] + #[doc = " @param[in,out] message message to operate on."] + #[doc = " @param[in] key key to delete properties for. If NULL, delete"] + #[doc = "\t\t\t properties for all keys"] + #[doc = " @returns"] + #[doc = " - NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in"] + #[doc = " read-only mode so message cannot be modified."] + #[doc = " - NOTMUCH_STATUS_SUCCESS: No error occurred."] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_message_remove_all_properties( + message: *mut notmuch_message_t, + key: *const ::std::os::raw::c_char, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Remove all (prefix*,value) pairs from the given message"] + #[doc = ""] + #[doc = " @param[in,out] message message to operate on."] + #[doc = " @param[in] prefix delete properties with keys that start with prefix."] + #[doc = "\t\t\t If NULL, delete all properties"] + #[doc = " @returns"] + #[doc = " - NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in"] + #[doc = " read-only mode so message cannot be modified."] + #[doc = " - NOTMUCH_STATUS_SUCCESS: No error occurred."] + #[doc = ""] + #[doc = " @since libnotmuch 5.1 (notmuch 0.26)"] + pub fn notmuch_message_remove_all_properties_with_prefix( + message: *mut notmuch_message_t, + prefix: *const ::std::os::raw::c_char, + ) -> notmuch_status_t; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _notmuch_string_map_iterator { + _unused: [u8; 0], +} +#[doc = " Opaque message property iterator"] +pub type notmuch_message_properties_t = _notmuch_string_map_iterator; +extern "C" { + #[doc = " Get the properties for *message*, returning a"] + #[doc = " notmuch_message_properties_t object which can be used to iterate"] + #[doc = " over all properties."] + #[doc = ""] + #[doc = " The notmuch_message_properties_t object is owned by the message and"] + #[doc = " as such, will only be valid for as long as the message is valid,"] + #[doc = " (which is until the query from which it derived is destroyed)."] + #[doc = ""] + #[doc = " @param[in] message The message to examine"] + #[doc = " @param[in] key key or key prefix"] + #[doc = " @param[in] exact if TRUE, require exact match with key. Otherwise"] + #[doc = "\t\t treat as prefix."] + #[doc = ""] + #[doc = " Typical usage might be:"] + #[doc = ""] + #[doc = " notmuch_message_properties_t *list;"] + #[doc = ""] + #[doc = " for (list = notmuch_message_get_properties (message, \"testkey1\", TRUE);"] + #[doc = " notmuch_message_properties_valid (list); notmuch_message_properties_move_to_next (list)) {"] + #[doc = " printf(\"%s\\n\", notmuch_message_properties_value(list));"] + #[doc = " }"] + #[doc = ""] + #[doc = " notmuch_message_properties_destroy (list);"] + #[doc = ""] + #[doc = " Note that there's no explicit destructor needed for the"] + #[doc = " notmuch_message_properties_t object. (For consistency, we do"] + #[doc = " provide a notmuch_message_properities_destroy function, but there's"] + #[doc = " no good reason to call it if the message is about to be destroyed)."] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_message_get_properties( + message: *mut notmuch_message_t, + key: *const ::std::os::raw::c_char, + exact: notmuch_bool_t, + ) -> *mut notmuch_message_properties_t; +} +extern "C" { + #[doc = " Return the number of properties named \"key\" belonging to the specific message."] + #[doc = ""] + #[doc = " @param[in] message The message to examine"] + #[doc = " @param[in] key key to count"] + #[doc = " @param[out] count The number of matching properties associated with this message."] + #[doc = ""] + #[doc = " @returns"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: successful count, possibly some other error."] + #[doc = ""] + #[doc = " @since libnotmuch 5.2 (notmuch 0.27)"] + pub fn notmuch_message_count_properties( + message: *mut notmuch_message_t, + key: *const ::std::os::raw::c_char, + count: *mut ::std::os::raw::c_uint, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Is the given *properties* iterator pointing at a valid (key,value)"] + #[doc = " pair."] + #[doc = ""] + #[doc = " When this function returns TRUE,"] + #[doc = " notmuch_message_properties_{key,value} will return a valid string,"] + #[doc = " and notmuch_message_properties_move_to_next will do what it"] + #[doc = " says. Whereas when this function returns FALSE, calling any of"] + #[doc = " these functions results in undefined behaviour."] + #[doc = ""] + #[doc = " See the documentation of notmuch_message_get_properties for example"] + #[doc = " code showing how to iterate over a notmuch_message_properties_t"] + #[doc = " object."] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_message_properties_valid( + properties: *mut notmuch_message_properties_t, + ) -> notmuch_bool_t; +} +extern "C" { + #[doc = " Move the *properties* iterator to the next (key,value) pair"] + #[doc = ""] + #[doc = " If *properties* is already pointing at the last pair then the iterator"] + #[doc = " will be moved to a point just beyond that last pair, (where"] + #[doc = " notmuch_message_properties_valid will return FALSE)."] + #[doc = ""] + #[doc = " See the documentation of notmuch_message_get_properties for example"] + #[doc = " code showing how to iterate over a notmuch_message_properties_t object."] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_message_properties_move_to_next(properties: *mut notmuch_message_properties_t); +} +extern "C" { + #[doc = " Return the key from the current (key,value) pair."] + #[doc = ""] + #[doc = " this could be useful if iterating for a prefix"] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_message_properties_key( + properties: *mut notmuch_message_properties_t, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Return the value from the current (key,value) pair."] + #[doc = ""] + #[doc = " This could be useful if iterating for a prefix."] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_message_properties_value( + properties: *mut notmuch_message_properties_t, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Destroy a notmuch_message_properties_t object."] + #[doc = ""] + #[doc = " It's not strictly necessary to call this function. All memory from"] + #[doc = " the notmuch_message_properties_t object will be reclaimed when the"] + #[doc = " containing message object is destroyed."] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_message_properties_destroy(properties: *mut notmuch_message_properties_t); +} +extern "C" { + #[doc = " Is the given 'tags' iterator pointing at a valid tag."] + #[doc = ""] + #[doc = " When this function returns TRUE, notmuch_tags_get will return a"] + #[doc = " valid string. Whereas when this function returns FALSE,"] + #[doc = " notmuch_tags_get will return NULL."] + #[doc = ""] + #[doc = " See the documentation of notmuch_message_get_tags for example code"] + #[doc = " showing how to iterate over a notmuch_tags_t object."] + pub fn notmuch_tags_valid(tags: *mut notmuch_tags_t) -> notmuch_bool_t; +} +extern "C" { + #[doc = " Get the current tag from 'tags' as a string."] + #[doc = ""] + #[doc = " Note: The returned string belongs to 'tags' and has a lifetime"] + #[doc = " identical to it (and the query to which it ultimately belongs)."] + #[doc = ""] + #[doc = " See the documentation of notmuch_message_get_tags for example code"] + #[doc = " showing how to iterate over a notmuch_tags_t object."] + pub fn notmuch_tags_get(tags: *mut notmuch_tags_t) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Move the 'tags' iterator to the next tag."] + #[doc = ""] + #[doc = " If 'tags' is already pointing at the last tag then the iterator"] + #[doc = " will be moved to a point just beyond that last tag, (where"] + #[doc = " notmuch_tags_valid will return FALSE and notmuch_tags_get will"] + #[doc = " return NULL)."] + #[doc = ""] + #[doc = " See the documentation of notmuch_message_get_tags for example code"] + #[doc = " showing how to iterate over a notmuch_tags_t object."] + pub fn notmuch_tags_move_to_next(tags: *mut notmuch_tags_t); +} +extern "C" { + #[doc = " Destroy a notmuch_tags_t object."] + #[doc = ""] + #[doc = " It's not strictly necessary to call this function. All memory from"] + #[doc = " the notmuch_tags_t object will be reclaimed when the containing"] + #[doc = " message or query objects are destroyed."] + pub fn notmuch_tags_destroy(tags: *mut notmuch_tags_t); +} +extern "C" { + #[doc = " Store an mtime within the database for 'directory'."] + #[doc = ""] + #[doc = " The 'directory' should be an object retrieved from the database"] + #[doc = " with notmuch_database_get_directory for a particular path."] + #[doc = ""] + #[doc = " The intention is for the caller to use the mtime to allow efficient"] + #[doc = " identification of new messages to be added to the database. The"] + #[doc = " recommended usage is as follows:"] + #[doc = ""] + #[doc = " o Read the mtime of a directory from the filesystem"] + #[doc = ""] + #[doc = " o Call index_file for all mail files in the directory"] + #[doc = ""] + #[doc = " o Call notmuch_directory_set_mtime with the mtime read from the"] + #[doc = " filesystem."] + #[doc = ""] + #[doc = " Then, when wanting to check for updates to the directory in the"] + #[doc = " future, the client can call notmuch_directory_get_mtime and know"] + #[doc = " that it only needs to add files if the mtime of the directory and"] + #[doc = " files are newer than the stored timestamp."] + #[doc = ""] + #[doc = " Note: The notmuch_directory_get_mtime function does not allow the"] + #[doc = " caller to distinguish a timestamp of 0 from a non-existent"] + #[doc = " timestamp. So don't store a timestamp of 0 unless you are"] + #[doc = " comfortable with that."] + #[doc = ""] + #[doc = " Return value:"] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_SUCCESS: mtime successfully stored in database."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception"] + #[doc = "\toccurred, mtime not stored."] + #[doc = ""] + #[doc = " NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only"] + #[doc = "\tmode so directory mtime cannot be modified."] + pub fn notmuch_directory_set_mtime( + directory: *mut notmuch_directory_t, + mtime: time_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Get the mtime of a directory, (as previously stored with"] + #[doc = " notmuch_directory_set_mtime)."] + #[doc = ""] + #[doc = " Returns 0 if no mtime has previously been stored for this"] + #[doc = " directory."] + pub fn notmuch_directory_get_mtime(directory: *mut notmuch_directory_t) -> time_t; +} +extern "C" { + #[doc = " Get a notmuch_filenames_t iterator listing all the filenames of"] + #[doc = " messages in the database within the given directory."] + #[doc = ""] + #[doc = " The returned filenames will be the basename-entries only (not"] + #[doc = " complete paths)."] + pub fn notmuch_directory_get_child_files( + directory: *mut notmuch_directory_t, + ) -> *mut notmuch_filenames_t; +} +extern "C" { + #[doc = " Get a notmuch_filenames_t iterator listing all the filenames of"] + #[doc = " sub-directories in the database within the given directory."] + #[doc = ""] + #[doc = " The returned filenames will be the basename-entries only (not"] + #[doc = " complete paths)."] + pub fn notmuch_directory_get_child_directories( + directory: *mut notmuch_directory_t, + ) -> *mut notmuch_filenames_t; +} +extern "C" { + #[doc = " Delete directory document from the database, and destroy the"] + #[doc = " notmuch_directory_t object. Assumes any child directories and files"] + #[doc = " have been deleted by the caller."] + #[doc = ""] + #[doc = " @since libnotmuch 4.3 (notmuch 0.21)"] + pub fn notmuch_directory_delete(directory: *mut notmuch_directory_t) -> notmuch_status_t; +} +extern "C" { + #[doc = " Destroy a notmuch_directory_t object."] + pub fn notmuch_directory_destroy(directory: *mut notmuch_directory_t); +} +extern "C" { + #[doc = " Is the given 'filenames' iterator pointing at a valid filename."] + #[doc = ""] + #[doc = " When this function returns TRUE, notmuch_filenames_get will return"] + #[doc = " a valid string. Whereas when this function returns FALSE,"] + #[doc = " notmuch_filenames_get will return NULL."] + #[doc = ""] + #[doc = " It is acceptable to pass NULL for 'filenames', in which case this"] + #[doc = " function will always return FALSE."] + pub fn notmuch_filenames_valid(filenames: *mut notmuch_filenames_t) -> notmuch_bool_t; +} +extern "C" { + #[doc = " Get the current filename from 'filenames' as a string."] + #[doc = ""] + #[doc = " Note: The returned string belongs to 'filenames' and has a lifetime"] + #[doc = " identical to it (and the directory to which it ultimately belongs)."] + #[doc = ""] + #[doc = " It is acceptable to pass NULL for 'filenames', in which case this"] + #[doc = " function will always return NULL."] + pub fn notmuch_filenames_get( + filenames: *mut notmuch_filenames_t, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Move the 'filenames' iterator to the next filename."] + #[doc = ""] + #[doc = " If 'filenames' is already pointing at the last filename then the"] + #[doc = " iterator will be moved to a point just beyond that last filename,"] + #[doc = " (where notmuch_filenames_valid will return FALSE and"] + #[doc = " notmuch_filenames_get will return NULL)."] + #[doc = ""] + #[doc = " It is acceptable to pass NULL for 'filenames', in which case this"] + #[doc = " function will do nothing."] + pub fn notmuch_filenames_move_to_next(filenames: *mut notmuch_filenames_t); +} +extern "C" { + #[doc = " Destroy a notmuch_filenames_t object."] + #[doc = ""] + #[doc = " It's not strictly necessary to call this function. All memory from"] + #[doc = " the notmuch_filenames_t object will be reclaimed when the"] + #[doc = " containing directory object is destroyed."] + #[doc = ""] + #[doc = " It is acceptable to pass NULL for 'filenames', in which case this"] + #[doc = " function will do nothing."] + pub fn notmuch_filenames_destroy(filenames: *mut notmuch_filenames_t); +} +extern "C" { + #[doc = " set config 'key' to 'value'"] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_database_set_config( + db: *mut notmuch_database_t, + key: *const ::std::os::raw::c_char, + value: *const ::std::os::raw::c_char, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " retrieve config item 'key', assign to 'value'"] + #[doc = ""] + #[doc = " keys which have not been previously set with n_d_set_config will"] + #[doc = " return an empty string."] + #[doc = ""] + #[doc = " return value is allocated by malloc and should be freed by the"] + #[doc = " caller."] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_database_get_config( + db: *mut notmuch_database_t, + key: *const ::std::os::raw::c_char, + value: *mut *mut ::std::os::raw::c_char, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Create an iterator for all config items with keys matching a given prefix"] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_database_get_config_list( + db: *mut notmuch_database_t, + prefix: *const ::std::os::raw::c_char, + out: *mut *mut notmuch_config_list_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Is 'config_list' iterator valid (i.e. _key, _value, _move_to_next can be called)."] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_config_list_valid(config_list: *mut notmuch_config_list_t) -> notmuch_bool_t; +} +extern "C" { + #[doc = " return key for current config pair"] + #[doc = ""] + #[doc = " return value is owned by the iterator, and will be destroyed by the"] + #[doc = " next call to notmuch_config_list_key or notmuch_config_list_destroy."] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_config_list_key( + config_list: *mut notmuch_config_list_t, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " return 'value' for current config pair"] + #[doc = ""] + #[doc = " return value is owned by the iterator, and will be destroyed by the"] + #[doc = " next call to notmuch_config_list_value or notmuch config_list_destroy"] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_config_list_value( + config_list: *mut notmuch_config_list_t, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " move 'config_list' iterator to the next pair"] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_config_list_move_to_next(config_list: *mut notmuch_config_list_t); +} +extern "C" { + #[doc = " free any resources held by 'config_list'"] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_config_list_destroy(config_list: *mut notmuch_config_list_t); +} +extern "C" { + #[doc = " get the current default indexing options for a given database."] + #[doc = ""] + #[doc = " This object will survive until the database itself is destroyed,"] + #[doc = " but the caller may also release it earlier with"] + #[doc = " notmuch_indexopts_destroy."] + #[doc = ""] + #[doc = " This object represents a set of options on how a message can be"] + #[doc = " added to the index. At the moment it is a featureless stub."] + #[doc = ""] + #[doc = " @since libnotmuch 5.1 (notmuch 0.26)"] + pub fn notmuch_database_get_default_indexopts( + db: *mut notmuch_database_t, + ) -> *mut notmuch_indexopts_t; +} +pub const notmuch_decryption_policy_t_NOTMUCH_DECRYPT_FALSE: notmuch_decryption_policy_t = 0; +pub const notmuch_decryption_policy_t_NOTMUCH_DECRYPT_TRUE: notmuch_decryption_policy_t = 1; +pub const notmuch_decryption_policy_t_NOTMUCH_DECRYPT_AUTO: notmuch_decryption_policy_t = 2; +pub const notmuch_decryption_policy_t_NOTMUCH_DECRYPT_NOSTASH: notmuch_decryption_policy_t = 3; +#[doc = " Stating a policy about how to decrypt messages."] +#[doc = ""] +#[doc = " See index.decrypt in notmuch-config(1) for more details."] +pub type notmuch_decryption_policy_t = u32; +extern "C" { + #[doc = " Specify whether to decrypt encrypted parts while indexing."] + #[doc = ""] + #[doc = " Be aware that the index is likely sufficient to reconstruct the"] + #[doc = " cleartext of the message itself, so please ensure that the notmuch"] + #[doc = " message index is adequately protected. DO NOT SET THIS FLAG TO TRUE"] + #[doc = " without considering the security of your index."] + #[doc = ""] + #[doc = " @since libnotmuch 5.1 (notmuch 0.26)"] + pub fn notmuch_indexopts_set_decrypt_policy( + indexopts: *mut notmuch_indexopts_t, + decrypt_policy: notmuch_decryption_policy_t, + ) -> notmuch_status_t; +} +extern "C" { + #[doc = " Return whether to decrypt encrypted parts while indexing."] + #[doc = " see notmuch_indexopts_set_decrypt_policy."] + #[doc = ""] + #[doc = " @since libnotmuch 5.1 (notmuch 0.26)"] + pub fn notmuch_indexopts_get_decrypt_policy( + indexopts: *const notmuch_indexopts_t, + ) -> notmuch_decryption_policy_t; +} +extern "C" { + #[doc = " Destroy a notmuch_indexopts_t object."] + #[doc = ""] + #[doc = " @since libnotmuch 5.1 (notmuch 0.26)"] + pub fn notmuch_indexopts_destroy(options: *mut notmuch_indexopts_t); +} +extern "C" { + #[doc = " interrogate the library for compile time features"] + #[doc = ""] + #[doc = " @since libnotmuch 4.4 (notmuch 0.23)"] + pub fn notmuch_built_with(name: *const ::std::os::raw::c_char) -> notmuch_bool_t; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __locale_data { + pub _address: u8, +} diff --git a/melib/src/backends/notmuch/notmuch.h b/melib/src/backends/notmuch/notmuch.h new file mode 100644 index 00000000..34666b88 --- /dev/null +++ b/melib/src/backends/notmuch/notmuch.h @@ -0,0 +1,2321 @@ +/* notmuch - Not much of an email library, (just index and search) + * + * Copyright © 2009 Carl Worth + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/ . + * + * Author: Carl Worth + */ + +/** + * @defgroup notmuch The notmuch API + * + * Not much of an email library, (just index and search) + * + * @{ + */ + +#ifndef NOTMUCH_H +#define NOTMUCH_H + +#ifndef __DOXYGEN__ + +#ifdef __cplusplus +# define NOTMUCH_BEGIN_DECLS extern "C" { +# define NOTMUCH_END_DECLS } +#else +# define NOTMUCH_BEGIN_DECLS +# define NOTMUCH_END_DECLS +#endif + +NOTMUCH_BEGIN_DECLS + +#include + +#pragma GCC visibility push(default) + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +/* + * The library version number. This must agree with the soname + * version in Makefile.local. + */ +#define LIBNOTMUCH_MAJOR_VERSION 5 +#define LIBNOTMUCH_MINOR_VERSION 2 +#define LIBNOTMUCH_MICRO_VERSION 0 + + +#if defined (__clang_major__) && __clang_major__ >= 3 \ + || defined (__GNUC__) && __GNUC__ >= 5 \ + || defined (__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 5 +#define NOTMUCH_DEPRECATED(major, minor) \ + __attribute__ ((deprecated ("function deprecated as of libnotmuch " #major "." #minor))) +#else +#define NOTMUCH_DEPRECATED(major, minor) __attribute__ ((deprecated)) +#endif + + +#endif /* __DOXYGEN__ */ + +/** + * Check the version of the notmuch library being compiled against. + * + * Return true if the library being compiled against is of the + * specified version or above. For example: + * + * @code + * #if LIBNOTMUCH_CHECK_VERSION(3, 1, 0) + * (code requiring libnotmuch 3.1.0 or above) + * #endif + * @endcode + * + * LIBNOTMUCH_CHECK_VERSION has been defined since version 3.1.0; to + * check for versions prior to that, use: + * + * @code + * #if !defined(NOTMUCH_CHECK_VERSION) + * (code requiring libnotmuch prior to 3.1.0) + * #endif + * @endcode + */ +#define LIBNOTMUCH_CHECK_VERSION(major, minor, micro) \ + (LIBNOTMUCH_MAJOR_VERSION > (major) || \ + (LIBNOTMUCH_MAJOR_VERSION == (major) && LIBNOTMUCH_MINOR_VERSION > (minor)) || \ + (LIBNOTMUCH_MAJOR_VERSION == (major) && LIBNOTMUCH_MINOR_VERSION == (minor) && \ + LIBNOTMUCH_MICRO_VERSION >= (micro))) + +/** + * Notmuch boolean type. + */ +typedef int notmuch_bool_t; + +/** + * Status codes used for the return values of most functions. + * + * A zero value (NOTMUCH_STATUS_SUCCESS) indicates that the function + * completed without error. Any other value indicates an error. + */ +typedef enum _notmuch_status { + /** + * No error occurred. + */ + NOTMUCH_STATUS_SUCCESS = 0, + /** + * Out of memory. + */ + NOTMUCH_STATUS_OUT_OF_MEMORY, + /** + * An attempt was made to write to a database opened in read-only + * mode. + */ + NOTMUCH_STATUS_READ_ONLY_DATABASE, + /** + * A Xapian exception occurred. + * + * @todo We don't really want to expose this lame XAPIAN_EXCEPTION + * value. Instead we should map to things like DATABASE_LOCKED or + * whatever. + */ + NOTMUCH_STATUS_XAPIAN_EXCEPTION, + /** + * An error occurred trying to read or write to a file (this could + * be file not found, permission denied, etc.) + */ + NOTMUCH_STATUS_FILE_ERROR, + /** + * A file was presented that doesn't appear to be an email + * message. + */ + NOTMUCH_STATUS_FILE_NOT_EMAIL, + /** + * A file contains a message ID that is identical to a message + * already in the database. + */ + NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID, + /** + * The user erroneously passed a NULL pointer to a notmuch + * function. + */ + NOTMUCH_STATUS_NULL_POINTER, + /** + * A tag value is too long (exceeds NOTMUCH_TAG_MAX). + */ + NOTMUCH_STATUS_TAG_TOO_LONG, + /** + * The notmuch_message_thaw function has been called more times + * than notmuch_message_freeze. + */ + NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW, + /** + * notmuch_database_end_atomic has been called more times than + * notmuch_database_begin_atomic. + */ + NOTMUCH_STATUS_UNBALANCED_ATOMIC, + /** + * The operation is not supported. + */ + NOTMUCH_STATUS_UNSUPPORTED_OPERATION, + /** + * The operation requires a database upgrade. + */ + NOTMUCH_STATUS_UPGRADE_REQUIRED, + /** + * There is a problem with the proposed path, e.g. a relative path + * passed to a function expecting an absolute path. + */ + NOTMUCH_STATUS_PATH_ERROR, + /** + * The requested operation was ignored. Depending on the function, + * this may not be an actual error. + */ + NOTMUCH_STATUS_IGNORED, + /** + * One of the arguments violates the preconditions for the + * function, in a way not covered by a more specific argument. + */ + NOTMUCH_STATUS_ILLEGAL_ARGUMENT, + /** + * A MIME object claimed to have cryptographic protection which + * notmuch tried to handle, but the protocol was not specified in + * an intelligible way. + */ + NOTMUCH_STATUS_MALFORMED_CRYPTO_PROTOCOL, + /** + * Notmuch attempted to do crypto processing, but could not + * initialize the engine needed to do so. + */ + NOTMUCH_STATUS_FAILED_CRYPTO_CONTEXT_CREATION, + /** + * A MIME object claimed to have cryptographic protection, and + * notmuch attempted to process it, but the specific protocol was + * something that notmuch doesn't know how to handle. + */ + NOTMUCH_STATUS_UNKNOWN_CRYPTO_PROTOCOL, + /** + * Not an actual status value. Just a way to find out how many + * valid status values there are. + */ + NOTMUCH_STATUS_LAST_STATUS +} notmuch_status_t; + +/** + * Get a string representation of a notmuch_status_t value. + * + * The result is read-only. + */ +const char * +notmuch_status_to_string (notmuch_status_t status); + +/* Various opaque data types. For each notmuch__t see the various + * notmuch_ functions below. */ +#ifndef __DOXYGEN__ +typedef struct _notmuch_database notmuch_database_t; +typedef struct _notmuch_query notmuch_query_t; +typedef struct _notmuch_threads notmuch_threads_t; +typedef struct _notmuch_thread notmuch_thread_t; +typedef struct _notmuch_messages notmuch_messages_t; +typedef struct _notmuch_message notmuch_message_t; +typedef struct _notmuch_tags notmuch_tags_t; +typedef struct _notmuch_directory notmuch_directory_t; +typedef struct _notmuch_filenames notmuch_filenames_t; +typedef struct _notmuch_config_list notmuch_config_list_t; +typedef struct _notmuch_indexopts notmuch_indexopts_t; +#endif /* __DOXYGEN__ */ + +/** + * Create a new, empty notmuch database located at 'path'. + * + * The path should be a top-level directory to a collection of + * plain-text email messages (one message per file). This call will + * create a new ".notmuch" directory within 'path' where notmuch will + * store its data. + * + * After a successful call to notmuch_database_create, the returned + * database will be open so the caller should call + * notmuch_database_destroy when finished with it. + * + * The database will not yet have any data in it + * (notmuch_database_create itself is a very cheap function). Messages + * contained within 'path' can be added to the database by calling + * notmuch_database_index_file. + * + * In case of any failure, this function returns an error status and + * sets *database to NULL (after printing an error message on stderr). + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Successfully created the database. + * + * NOTMUCH_STATUS_NULL_POINTER: The given 'path' argument is NULL. + * + * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory. + * + * NOTMUCH_STATUS_FILE_ERROR: An error occurred trying to create the + * database file (such as permission denied, or file not found, + * etc.), or the database already exists. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred. + */ +notmuch_status_t +notmuch_database_create (const char *path, notmuch_database_t **database); + +/** + * Like notmuch_database_create, except optionally return an error + * message. This message is allocated by malloc and should be freed by + * the caller. + */ +notmuch_status_t +notmuch_database_create_verbose (const char *path, + notmuch_database_t **database, + char **error_message); + +/** + * Database open mode for notmuch_database_open. + */ +typedef enum { + /** + * Open database for reading only. + */ + NOTMUCH_DATABASE_MODE_READ_ONLY = 0, + /** + * Open database for reading and writing. + */ + NOTMUCH_DATABASE_MODE_READ_WRITE +} notmuch_database_mode_t; + +/** + * Open an existing notmuch database located at 'path'. + * + * The database should have been created at some time in the past, + * (not necessarily by this process), by calling + * notmuch_database_create with 'path'. By default the database should be + * opened for reading only. In order to write to the database you need to + * pass the NOTMUCH_DATABASE_MODE_READ_WRITE mode. + * + * An existing notmuch database can be identified by the presence of a + * directory named ".notmuch" below 'path'. + * + * The caller should call notmuch_database_destroy when finished with + * this database. + * + * In case of any failure, this function returns an error status and + * sets *database to NULL (after printing an error message on stderr). + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Successfully opened the database. + * + * NOTMUCH_STATUS_NULL_POINTER: The given 'path' argument is NULL. + * + * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory. + * + * NOTMUCH_STATUS_FILE_ERROR: An error occurred trying to open the + * database file (such as permission denied, or file not found, + * etc.), or the database version is unknown. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred. + */ +notmuch_status_t +notmuch_database_open (const char *path, + notmuch_database_mode_t mode, + notmuch_database_t **database); +/** + * Like notmuch_database_open, except optionally return an error + * message. This message is allocated by malloc and should be freed by + * the caller. + */ + +notmuch_status_t +notmuch_database_open_verbose (const char *path, + notmuch_database_mode_t mode, + notmuch_database_t **database, + char **error_message); + +/** + * Retrieve last status string for given database. + * + */ +const char * +notmuch_database_status_string (const notmuch_database_t *notmuch); + +/** + * Commit changes and close the given notmuch database. + * + * After notmuch_database_close has been called, calls to other + * functions on objects derived from this database may either behave + * as if the database had not been closed (e.g., if the required data + * has been cached) or may fail with a + * NOTMUCH_STATUS_XAPIAN_EXCEPTION. The only further operation + * permitted on the database itself is to call + * notmuch_database_destroy. + * + * notmuch_database_close can be called multiple times. Later calls + * have no effect. + * + * For writable databases, notmuch_database_close commits all changes + * to disk before closing the database. If the caller is currently in + * an atomic section (there was a notmuch_database_begin_atomic + * without a matching notmuch_database_end_atomic), this will discard + * changes made in that atomic section (but still commit changes made + * prior to entering the atomic section). + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Successfully closed the database. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred; the + * database has been closed but there are no guarantees the + * changes to the database, if any, have been flushed to disk. + */ +notmuch_status_t +notmuch_database_close (notmuch_database_t *database); + +/** + * A callback invoked by notmuch_database_compact to notify the user + * of the progress of the compaction process. + */ +typedef void (*notmuch_compact_status_cb_t)(const char *message, void *closure); + +/** + * Compact a notmuch database, backing up the original database to the + * given path. + * + * The database will be opened with NOTMUCH_DATABASE_MODE_READ_WRITE + * during the compaction process to ensure no writes are made. + * + * If the optional callback function 'status_cb' is non-NULL, it will + * be called with diagnostic and informational messages. The argument + * 'closure' is passed verbatim to any callback invoked. + */ +notmuch_status_t +notmuch_database_compact (const char *path, + const char *backup_path, + notmuch_compact_status_cb_t status_cb, + void *closure); + +/** + * Destroy the notmuch database, closing it if necessary and freeing + * all associated resources. + * + * Return value as in notmuch_database_close if the database was open; + * notmuch_database_destroy itself has no failure modes. + */ +notmuch_status_t +notmuch_database_destroy (notmuch_database_t *database); + +/** + * Return the database path of the given database. + * + * The return value is a string owned by notmuch so should not be + * modified nor freed by the caller. + */ +const char * +notmuch_database_get_path (notmuch_database_t *database); + +/** + * Return the database format version of the given database. + */ +unsigned int +notmuch_database_get_version (notmuch_database_t *database); + +/** + * Can the database be upgraded to a newer database version? + * + * If this function returns TRUE, then the caller may call + * notmuch_database_upgrade to upgrade the database. If the caller + * does not upgrade an out-of-date database, then some functions may + * fail with NOTMUCH_STATUS_UPGRADE_REQUIRED. This always returns + * FALSE for a read-only database because there's no way to upgrade a + * read-only database. + */ +notmuch_bool_t +notmuch_database_needs_upgrade (notmuch_database_t *database); + +/** + * Upgrade the current database to the latest supported version. + * + * This ensures that all current notmuch functionality will be + * available on the database. After opening a database in read-write + * mode, it is recommended that clients check if an upgrade is needed + * (notmuch_database_needs_upgrade) and if so, upgrade with this + * function before making any modifications. If + * notmuch_database_needs_upgrade returns FALSE, this will be a no-op. + * + * The optional progress_notify callback can be used by the caller to + * provide progress indication to the user. If non-NULL it will be + * called periodically with 'progress' as a floating-point value in + * the range of [0.0 .. 1.0] indicating the progress made so far in + * the upgrade process. The argument 'closure' is passed verbatim to + * any callback invoked. + */ +notmuch_status_t +notmuch_database_upgrade (notmuch_database_t *database, + void (*progress_notify)(void *closure, + double progress), + void *closure); + +/** + * Begin an atomic database operation. + * + * Any modifications performed between a successful begin and a + * notmuch_database_end_atomic will be applied to the database + * atomically. Note that, unlike a typical database transaction, this + * only ensures atomicity, not durability; neither begin nor end + * necessarily flush modifications to disk. + * + * Atomic sections may be nested. begin_atomic and end_atomic must + * always be called in pairs. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Successfully entered atomic section. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred; + * atomic section not entered. + */ +notmuch_status_t +notmuch_database_begin_atomic (notmuch_database_t *notmuch); + +/** + * Indicate the end of an atomic database operation. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Successfully completed atomic section. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred; + * atomic section not ended. + * + * NOTMUCH_STATUS_UNBALANCED_ATOMIC: The database is not currently in + * an atomic section. + */ +notmuch_status_t +notmuch_database_end_atomic (notmuch_database_t *notmuch); + +/** + * Return the committed database revision and UUID. + * + * The database revision number increases monotonically with each + * commit to the database. Hence, all messages and message changes + * committed to the database (that is, visible to readers) have a last + * modification revision <= the committed database revision. Any + * messages committed in the future will be assigned a modification + * revision > the committed database revision. + * + * The UUID is a NUL-terminated opaque string that uniquely identifies + * this database. Two revision numbers are only comparable if they + * have the same database UUID. + */ +unsigned long +notmuch_database_get_revision (notmuch_database_t *notmuch, + const char **uuid); + +/** + * Retrieve a directory object from the database for 'path'. + * + * Here, 'path' should be a path relative to the path of 'database' + * (see notmuch_database_get_path), or else should be an absolute path + * with initial components that match the path of 'database'. + * + * If this directory object does not exist in the database, this + * returns NOTMUCH_STATUS_SUCCESS and sets *directory to NULL. + * + * Otherwise the returned directory object is owned by the database + * and as such, will only be valid until notmuch_database_destroy is + * called. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Successfully retrieved directory. + * + * NOTMUCH_STATUS_NULL_POINTER: The given 'directory' argument is NULL. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred; + * directory not retrieved. + * + * NOTMUCH_STATUS_UPGRADE_REQUIRED: The caller must upgrade the + * database to use this function. + */ +notmuch_status_t +notmuch_database_get_directory (notmuch_database_t *database, + const char *path, + notmuch_directory_t **directory); + +/** + * Add a message file to a database, indexing it for retrieval by + * future searches. If a message already exists with the same message + * ID as the specified file, their indexes will be merged, and this + * new filename will also be associated with the existing message. + * + * Here, 'filename' should be a path relative to the path of + * 'database' (see notmuch_database_get_path), or else should be an + * absolute filename with initial components that match the path of + * 'database'. + * + * The file should be a single mail message (not a multi-message mbox) + * that is expected to remain at its current location, (since the + * notmuch database will reference the filename, and will not copy the + * entire contents of the file. + * + * If another message with the same message ID already exists in the + * database, rather than creating a new message, this adds the search + * terms from the identified file to the existing message's index, and + * adds 'filename' to the list of filenames known for the message. + * + * The 'indexopts' parameter can be NULL (meaning, use the indexing + * defaults from the database), or can be an explicit choice of + * indexing options that should govern the indexing of this specific + * 'filename'. + * + * If 'message' is not NULL, then, on successful return + * (NOTMUCH_STATUS_SUCCESS or NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) '*message' + * will be initialized to a message object that can be used for things + * such as adding tags to the just-added message. The user should call + * notmuch_message_destroy when done with the message. On any failure + * '*message' will be set to NULL. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Message successfully added to database. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred, + * message not added. + * + * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: Message has the same message + * ID as another message already in the database. The new + * filename was successfully added to the message in the database + * (if not already present) and the existing message is returned. + * + * NOTMUCH_STATUS_FILE_ERROR: an error occurred trying to open the + * file, (such as permission denied, or file not found, + * etc.). Nothing added to the database. + * + * NOTMUCH_STATUS_FILE_NOT_EMAIL: the contents of filename don't look + * like an email message. Nothing added to the database. + * + * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only + * mode so no message can be added. + * + * NOTMUCH_STATUS_UPGRADE_REQUIRED: The caller must upgrade the + * database to use this function. + * + * @since libnotmuch 5.1 (notmuch 0.26) + */ +notmuch_status_t +notmuch_database_index_file (notmuch_database_t *database, + const char *filename, + notmuch_indexopts_t *indexopts, + notmuch_message_t **message); + +/** + * Deprecated alias for notmuch_database_index_file called with + * NULL indexopts. + * + * @deprecated Deprecated as of libnotmuch 5.1 (notmuch 0.26). Please + * use notmuch_database_index_file instead. + * + */ +NOTMUCH_DEPRECATED (5, 1) +notmuch_status_t +notmuch_database_add_message (notmuch_database_t *database, + const char *filename, + notmuch_message_t **message); + +/** + * Remove a message filename from the given notmuch database. If the + * message has no more filenames, remove the message. + * + * If the same message (as determined by the message ID) is still + * available via other filenames, then the message will persist in the + * database for those filenames. When the last filename is removed for + * a particular message, the database content for that message will be + * entirely removed. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: The last filename was removed and the + * message was removed from the database. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred, + * message not removed. + * + * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: This filename was removed but + * the message persists in the database with at least one other + * filename. + * + * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only + * mode so no message can be removed. + * + * NOTMUCH_STATUS_UPGRADE_REQUIRED: The caller must upgrade the + * database to use this function. + */ +notmuch_status_t +notmuch_database_remove_message (notmuch_database_t *database, + const char *filename); + +/** + * Find a message with the given message_id. + * + * If a message with the given message_id is found then, on successful return + * (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to a message + * object. The caller should call notmuch_message_destroy when done with the + * message. + * + * On any failure or when the message is not found, this function initializes + * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the + * caller is supposed to check '*message' for NULL to find out whether the + * message with the given message_id was found. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'. + * + * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL + * + * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating message object + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred + */ +notmuch_status_t +notmuch_database_find_message (notmuch_database_t *database, + const char *message_id, + notmuch_message_t **message); + +/** + * Find a message with the given filename. + * + * If the database contains a message with the given filename then, on + * successful return (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to + * a message object. The caller should call notmuch_message_destroy when done + * with the message. + * + * On any failure or when the message is not found, this function initializes + * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the + * caller is supposed to check '*message' for NULL to find out whether the + * message with the given filename is found. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message' + * + * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL + * + * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating the message object + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred + * + * NOTMUCH_STATUS_UPGRADE_REQUIRED: The caller must upgrade the + * database to use this function. + */ +notmuch_status_t +notmuch_database_find_message_by_filename (notmuch_database_t *notmuch, + const char *filename, + notmuch_message_t **message); + +/** + * Return a list of all tags found in the database. + * + * This function creates a list of all tags found in the database. The + * resulting list contains all tags from all messages found in the database. + * + * On error this function returns NULL. + */ +notmuch_tags_t * +notmuch_database_get_all_tags (notmuch_database_t *db); + +/** + * Create a new query for 'database'. + * + * Here, 'database' should be an open database, (see + * notmuch_database_open and notmuch_database_create). + * + * For the query string, we'll document the syntax here more + * completely in the future, but it's likely to be a specialized + * version of the general Xapian query syntax: + * + * https://xapian.org/docs/queryparser.html + * + * As a special case, passing either a length-zero string, (that is ""), + * or a string consisting of a single asterisk (that is "*"), will + * result in a query that returns all messages in the database. + * + * See notmuch_query_set_sort for controlling the order of results. + * See notmuch_query_search_messages and notmuch_query_search_threads + * to actually execute the query. + * + * User should call notmuch_query_destroy when finished with this + * query. + * + * Will return NULL if insufficient memory is available. + */ +notmuch_query_t * +notmuch_query_create (notmuch_database_t *database, + const char *query_string); + +/** + * Sort values for notmuch_query_set_sort. + */ +typedef enum { + /** + * Oldest first. + */ + NOTMUCH_SORT_OLDEST_FIRST, + /** + * Newest first. + */ + NOTMUCH_SORT_NEWEST_FIRST, + /** + * Sort by message-id. + */ + NOTMUCH_SORT_MESSAGE_ID, + /** + * Do not sort. + */ + NOTMUCH_SORT_UNSORTED +} notmuch_sort_t; + +/** + * Return the query_string of this query. See notmuch_query_create. + */ +const char * +notmuch_query_get_query_string (const notmuch_query_t *query); + +/** + * Return the notmuch database of this query. See notmuch_query_create. + */ +notmuch_database_t * +notmuch_query_get_database (const notmuch_query_t *query); + +/** + * Exclude values for notmuch_query_set_omit_excluded. The strange + * order is to maintain backward compatibility: the old FALSE/TRUE + * options correspond to the new + * NOTMUCH_EXCLUDE_FLAG/NOTMUCH_EXCLUDE_TRUE options. + */ +typedef enum { + NOTMUCH_EXCLUDE_FLAG, + NOTMUCH_EXCLUDE_TRUE, + NOTMUCH_EXCLUDE_FALSE, + NOTMUCH_EXCLUDE_ALL +} notmuch_exclude_t; + +/** + * Specify whether to omit excluded results or simply flag them. By + * default, this is set to TRUE. + * + * If set to TRUE or ALL, notmuch_query_search_messages will omit excluded + * messages from the results, and notmuch_query_search_threads will omit + * threads that match only in excluded messages. If set to TRUE, + * notmuch_query_search_threads will include all messages in threads that + * match in at least one non-excluded message. Otherwise, if set to ALL, + * notmuch_query_search_threads will omit excluded messages from all threads. + * + * If set to FALSE or FLAG then both notmuch_query_search_messages and + * notmuch_query_search_threads will return all matching + * messages/threads regardless of exclude status. If set to FLAG then + * the exclude flag will be set for any excluded message that is + * returned by notmuch_query_search_messages, and the thread counts + * for threads returned by notmuch_query_search_threads will be the + * number of non-excluded messages/matches. Otherwise, if set to + * FALSE, then the exclude status is completely ignored. + * + * The performance difference when calling + * notmuch_query_search_messages should be relatively small (and both + * should be very fast). However, in some cases, + * notmuch_query_search_threads is very much faster when omitting + * excluded messages as it does not need to construct the threads that + * only match in excluded messages. + */ +void +notmuch_query_set_omit_excluded (notmuch_query_t *query, + notmuch_exclude_t omit_excluded); + +/** + * Specify the sorting desired for this query. + */ +void +notmuch_query_set_sort (notmuch_query_t *query, notmuch_sort_t sort); + +/** + * Return the sort specified for this query. See + * notmuch_query_set_sort. + */ +notmuch_sort_t +notmuch_query_get_sort (const notmuch_query_t *query); + +/** + * Add a tag that will be excluded from the query results by default. + * This exclusion will be ignored if this tag appears explicitly in + * the query. + * + * @returns + * + * NOTMUCH_STATUS_SUCCESS: excluded was added successfully. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occurred. + * Most likely a problem lazily parsing the query string. + * + * NOTMUCH_STATUS_IGNORED: tag is explicitly present in the query, so + * not excluded. + */ +notmuch_status_t +notmuch_query_add_tag_exclude (notmuch_query_t *query, const char *tag); + +/** + * Execute a query for threads, returning a notmuch_threads_t object + * which can be used to iterate over the results. The returned threads + * object is owned by the query and as such, will only be valid until + * notmuch_query_destroy. + * + * Typical usage might be: + * + * notmuch_query_t *query; + * notmuch_threads_t *threads; + * notmuch_thread_t *thread; + * notmuch_status_t stat; + * + * query = notmuch_query_create (database, query_string); + * + * for (stat = notmuch_query_search_threads (query, &threads); + * stat == NOTMUCH_STATUS_SUCCESS && + * notmuch_threads_valid (threads); + * notmuch_threads_move_to_next (threads)) + * { + * thread = notmuch_threads_get (threads); + * .... + * notmuch_thread_destroy (thread); + * } + * + * notmuch_query_destroy (query); + * + * Note: If you are finished with a thread before its containing + * query, you can call notmuch_thread_destroy to clean up some memory + * sooner (as in the above example). Otherwise, if your thread objects + * are long-lived, then you don't need to call notmuch_thread_destroy + * and all the memory will still be reclaimed when the query is + * destroyed. + * + * Note that there's no explicit destructor needed for the + * notmuch_threads_t object. (For consistency, we do provide a + * notmuch_threads_destroy function, but there's no good reason + * to call it if the query is about to be destroyed). + * + * @since libnotmuch 5.0 (notmuch 0.25) + */ +notmuch_status_t +notmuch_query_search_threads (notmuch_query_t *query, + notmuch_threads_t **out); + +/** + * Deprecated alias for notmuch_query_search_threads. + * + * @deprecated Deprecated as of libnotmuch 5 (notmuch 0.25). Please + * use notmuch_query_search_threads instead. + * + */ +NOTMUCH_DEPRECATED (5, 0) +notmuch_status_t +notmuch_query_search_threads_st (notmuch_query_t *query, notmuch_threads_t **out); + +/** + * Execute a query for messages, returning a notmuch_messages_t object + * which can be used to iterate over the results. The returned + * messages object is owned by the query and as such, will only be + * valid until notmuch_query_destroy. + * + * Typical usage might be: + * + * notmuch_query_t *query; + * notmuch_messages_t *messages; + * notmuch_message_t *message; + * + * query = notmuch_query_create (database, query_string); + * + * for (messages = notmuch_query_search_messages (query); + * notmuch_messages_valid (messages); + * notmuch_messages_move_to_next (messages)) + * { + * message = notmuch_messages_get (messages); + * .... + * notmuch_message_destroy (message); + * } + * + * notmuch_query_destroy (query); + * + * Note: If you are finished with a message before its containing + * query, you can call notmuch_message_destroy to clean up some memory + * sooner (as in the above example). Otherwise, if your message + * objects are long-lived, then you don't need to call + * notmuch_message_destroy and all the memory will still be reclaimed + * when the query is destroyed. + * + * Note that there's no explicit destructor needed for the + * notmuch_messages_t object. (For consistency, we do provide a + * notmuch_messages_destroy function, but there's no good + * reason to call it if the query is about to be destroyed). + * + * If a Xapian exception occurs this function will return NULL. + * + * @since libnotmuch 5 (notmuch 0.25) + */ +notmuch_status_t +notmuch_query_search_messages (notmuch_query_t *query, + notmuch_messages_t **out); +/** + * Deprecated alias for notmuch_query_search_messages + * + * @deprecated Deprecated as of libnotmuch 5 (notmuch 0.25). Please use + * notmuch_query_search_messages instead. + * + */ + +NOTMUCH_DEPRECATED (5, 0) +notmuch_status_t +notmuch_query_search_messages_st (notmuch_query_t *query, + notmuch_messages_t **out); + +/** + * Destroy a notmuch_query_t along with any associated resources. + * + * This will in turn destroy any notmuch_threads_t and + * notmuch_messages_t objects generated by this query, (and in + * turn any notmuch_thread_t and notmuch_message_t objects generated + * from those results, etc.), if such objects haven't already been + * destroyed. + */ +void +notmuch_query_destroy (notmuch_query_t *query); + +/** + * Is the given 'threads' iterator pointing at a valid thread. + * + * When this function returns TRUE, notmuch_threads_get will return a + * valid object. Whereas when this function returns FALSE, + * notmuch_threads_get will return NULL. + * + * If passed a NULL pointer, this function returns FALSE + * + * See the documentation of notmuch_query_search_threads for example + * code showing how to iterate over a notmuch_threads_t object. + */ +notmuch_bool_t +notmuch_threads_valid (notmuch_threads_t *threads); + +/** + * Get the current thread from 'threads' as a notmuch_thread_t. + * + * Note: The returned thread belongs to 'threads' and has a lifetime + * identical to it (and the query to which it belongs). + * + * See the documentation of notmuch_query_search_threads for example + * code showing how to iterate over a notmuch_threads_t object. + * + * If an out-of-memory situation occurs, this function will return + * NULL. + */ +notmuch_thread_t * +notmuch_threads_get (notmuch_threads_t *threads); + +/** + * Move the 'threads' iterator to the next thread. + * + * If 'threads' is already pointing at the last thread then the + * iterator will be moved to a point just beyond that last thread, + * (where notmuch_threads_valid will return FALSE and + * notmuch_threads_get will return NULL). + * + * See the documentation of notmuch_query_search_threads for example + * code showing how to iterate over a notmuch_threads_t object. + */ +void +notmuch_threads_move_to_next (notmuch_threads_t *threads); + +/** + * Destroy a notmuch_threads_t object. + * + * It's not strictly necessary to call this function. All memory from + * the notmuch_threads_t object will be reclaimed when the + * containing query object is destroyed. + */ +void +notmuch_threads_destroy (notmuch_threads_t *threads); + +/** + * Return the number of messages matching a search. + * + * This function performs a search and returns the number of matching + * messages. + * + * @returns + * + * NOTMUCH_STATUS_SUCCESS: query completed successfully. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occurred. The + * value of *count is not defined. + * + * @since libnotmuch 5 (notmuch 0.25) + */ +notmuch_status_t +notmuch_query_count_messages (notmuch_query_t *query, unsigned int *count); + +/** + * Deprecated alias for notmuch_query_count_messages + * + * + * @deprecated Deprecated since libnotmuch 5.0 (notmuch 0.25). Please + * use notmuch_query_count_messages instead. + */ +NOTMUCH_DEPRECATED (5, 0) +notmuch_status_t +notmuch_query_count_messages_st (notmuch_query_t *query, unsigned int *count); + +/** + * Return the number of threads matching a search. + * + * This function performs a search and returns the number of unique thread IDs + * in the matching messages. This is the same as number of threads matching a + * search. + * + * Note that this is a significantly heavier operation than + * notmuch_query_count_messages{_st}(). + * + * @returns + * + * NOTMUCH_STATUS_OUT_OF_MEMORY: Memory allocation failed. The value + * of *count is not defined + * + * NOTMUCH_STATUS_SUCCESS: query completed successfully. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occurred. The + * value of *count is not defined. + * + * @since libnotmuch 5 (notmuch 0.25) + */ +notmuch_status_t +notmuch_query_count_threads (notmuch_query_t *query, unsigned *count); + +/** + * Deprecated alias for notmuch_query_count_threads + * + * @deprecated Deprecated as of libnotmuch 5.0 (notmuch 0.25). Please + * use notmuch_query_count_threads_st instead. + */ +NOTMUCH_DEPRECATED (5, 0) +notmuch_status_t +notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count); + +/** + * Get the thread ID of 'thread'. + * + * The returned string belongs to 'thread' and as such, should not be + * modified by the caller and will only be valid for as long as the + * thread is valid, (which is until notmuch_thread_destroy or until + * the query from which it derived is destroyed). + */ +const char * +notmuch_thread_get_thread_id (notmuch_thread_t *thread); + +/** + * Get the total number of messages in 'thread'. + * + * This count consists of all messages in the database belonging to + * this thread. Contrast with notmuch_thread_get_matched_messages() . + */ +int +notmuch_thread_get_total_messages (notmuch_thread_t *thread); + +/** + * Get the total number of files in 'thread'. + * + * This sums notmuch_message_count_files over all messages in the + * thread + * @returns Non-negative integer + * @since libnotmuch 5.0 (notmuch 0.25) + */ + +int +notmuch_thread_get_total_files (notmuch_thread_t *thread); + +/** + * Get a notmuch_messages_t iterator for the top-level messages in + * 'thread' in oldest-first order. + * + * This iterator will not necessarily iterate over all of the messages + * in the thread. It will only iterate over the messages in the thread + * which are not replies to other messages in the thread. + * + * The returned list will be destroyed when the thread is destroyed. + */ +notmuch_messages_t * +notmuch_thread_get_toplevel_messages (notmuch_thread_t *thread); + +/** + * Get a notmuch_thread_t iterator for all messages in 'thread' in + * oldest-first order. + * + * The returned list will be destroyed when the thread is destroyed. + */ +notmuch_messages_t * +notmuch_thread_get_messages (notmuch_thread_t *thread); + +/** + * Get the number of messages in 'thread' that matched the search. + * + * This count includes only the messages in this thread that were + * matched by the search from which the thread was created and were + * not excluded by any exclude tags passed in with the query (see + * notmuch_query_add_tag_exclude). Contrast with + * notmuch_thread_get_total_messages() . + */ +int +notmuch_thread_get_matched_messages (notmuch_thread_t *thread); + +/** + * Get the authors of 'thread' as a UTF-8 string. + * + * The returned string is a comma-separated list of the names of the + * authors of mail messages in the query results that belong to this + * thread. + * + * The string contains authors of messages matching the query first, then + * non-matched authors (with the two groups separated by '|'). Within + * each group, authors are ordered by date. + * + * The returned string belongs to 'thread' and as such, should not be + * modified by the caller and will only be valid for as long as the + * thread is valid, (which is until notmuch_thread_destroy or until + * the query from which it derived is destroyed). + */ +const char * +notmuch_thread_get_authors (notmuch_thread_t *thread); + +/** + * Get the subject of 'thread' as a UTF-8 string. + * + * The subject is taken from the first message (according to the query + * order---see notmuch_query_set_sort) in the query results that + * belongs to this thread. + * + * The returned string belongs to 'thread' and as such, should not be + * modified by the caller and will only be valid for as long as the + * thread is valid, (which is until notmuch_thread_destroy or until + * the query from which it derived is destroyed). + */ +const char * +notmuch_thread_get_subject (notmuch_thread_t *thread); + +/** + * Get the date of the oldest message in 'thread' as a time_t value. + */ +time_t +notmuch_thread_get_oldest_date (notmuch_thread_t *thread); + +/** + * Get the date of the newest message in 'thread' as a time_t value. + */ +time_t +notmuch_thread_get_newest_date (notmuch_thread_t *thread); + +/** + * Get the tags for 'thread', returning a notmuch_tags_t object which + * can be used to iterate over all tags. + * + * Note: In the Notmuch database, tags are stored on individual + * messages, not on threads. So the tags returned here will be all + * tags of the messages which matched the search and which belong to + * this thread. + * + * The tags object is owned by the thread and as such, will only be + * valid for as long as the thread is valid, (for example, until + * notmuch_thread_destroy or until the query from which it derived is + * destroyed). + * + * Typical usage might be: + * + * notmuch_thread_t *thread; + * notmuch_tags_t *tags; + * const char *tag; + * + * thread = notmuch_threads_get (threads); + * + * for (tags = notmuch_thread_get_tags (thread); + * notmuch_tags_valid (tags); + * notmuch_tags_move_to_next (tags)) + * { + * tag = notmuch_tags_get (tags); + * .... + * } + * + * notmuch_thread_destroy (thread); + * + * Note that there's no explicit destructor needed for the + * notmuch_tags_t object. (For consistency, we do provide a + * notmuch_tags_destroy function, but there's no good reason to call + * it if the message is about to be destroyed). + */ +notmuch_tags_t * +notmuch_thread_get_tags (notmuch_thread_t *thread); + +/** + * Destroy a notmuch_thread_t object. + */ +void +notmuch_thread_destroy (notmuch_thread_t *thread); + +/** + * Is the given 'messages' iterator pointing at a valid message. + * + * When this function returns TRUE, notmuch_messages_get will return a + * valid object. Whereas when this function returns FALSE, + * notmuch_messages_get will return NULL. + * + * See the documentation of notmuch_query_search_messages for example + * code showing how to iterate over a notmuch_messages_t object. + */ +notmuch_bool_t +notmuch_messages_valid (notmuch_messages_t *messages); + +/** + * Get the current message from 'messages' as a notmuch_message_t. + * + * Note: The returned message belongs to 'messages' and has a lifetime + * identical to it (and the query to which it belongs). + * + * See the documentation of notmuch_query_search_messages for example + * code showing how to iterate over a notmuch_messages_t object. + * + * If an out-of-memory situation occurs, this function will return + * NULL. + */ +notmuch_message_t * +notmuch_messages_get (notmuch_messages_t *messages); + +/** + * Move the 'messages' iterator to the next message. + * + * If 'messages' is already pointing at the last message then the + * iterator will be moved to a point just beyond that last message, + * (where notmuch_messages_valid will return FALSE and + * notmuch_messages_get will return NULL). + * + * See the documentation of notmuch_query_search_messages for example + * code showing how to iterate over a notmuch_messages_t object. + */ +void +notmuch_messages_move_to_next (notmuch_messages_t *messages); + +/** + * Destroy a notmuch_messages_t object. + * + * It's not strictly necessary to call this function. All memory from + * the notmuch_messages_t object will be reclaimed when the containing + * query object is destroyed. + */ +void +notmuch_messages_destroy (notmuch_messages_t *messages); + +/** + * Return a list of tags from all messages. + * + * The resulting list is guaranteed not to contain duplicated tags. + * + * WARNING: You can no longer iterate over messages after calling this + * function, because the iterator will point at the end of the list. + * We do not have a function to reset the iterator yet and the only + * way how you can iterate over the list again is to recreate the + * message list. + * + * The function returns NULL on error. + */ +notmuch_tags_t * +notmuch_messages_collect_tags (notmuch_messages_t *messages); + +/** + * Get the database associated with this message. + * + * @since libnotmuch 5.2 (notmuch 0.27) + */ +notmuch_database_t * +notmuch_message_get_database (const notmuch_message_t *message); + +/** + * Get the message ID of 'message'. + * + * The returned string belongs to 'message' and as such, should not be + * modified by the caller and will only be valid for as long as the + * message is valid, (which is until the query from which it derived + * is destroyed). + * + * This function will not return NULL since Notmuch ensures that every + * message has a unique message ID, (Notmuch will generate an ID for a + * message if the original file does not contain one). + */ +const char * +notmuch_message_get_message_id (notmuch_message_t *message); + +/** + * Get the thread ID of 'message'. + * + * The returned string belongs to 'message' and as such, should not be + * modified by the caller and will only be valid for as long as the + * message is valid, (for example, until the user calls + * notmuch_message_destroy on 'message' or until a query from which it + * derived is destroyed). + * + * This function will not return NULL since Notmuch ensures that every + * message belongs to a single thread. + */ +const char * +notmuch_message_get_thread_id (notmuch_message_t *message); + +/** + * Get a notmuch_messages_t iterator for all of the replies to + * 'message'. + * + * Note: This call only makes sense if 'message' was ultimately + * obtained from a notmuch_thread_t object, (such as by coming + * directly from the result of calling notmuch_thread_get_ + * toplevel_messages or by any number of subsequent + * calls to notmuch_message_get_replies). + * + * If 'message' was obtained through some non-thread means, (such as + * by a call to notmuch_query_search_messages), then this function + * will return NULL. + * + * If there are no replies to 'message', this function will return + * NULL. (Note that notmuch_messages_valid will accept that NULL + * value as legitimate, and simply return FALSE for it.) + * + * The returned list will be destroyed when the thread is destroyed. + */ +notmuch_messages_t * +notmuch_message_get_replies (notmuch_message_t *message); + +/** + * Get the total number of files associated with a message. + * @returns Non-negative integer + * @since libnotmuch 5.0 (notmuch 0.25) + */ +int +notmuch_message_count_files (notmuch_message_t *message); + +/** + * Get a filename for the email corresponding to 'message'. + * + * The returned filename is an absolute filename, (the initial + * component will match notmuch_database_get_path() ). + * + * The returned string belongs to the message so should not be + * modified or freed by the caller (nor should it be referenced after + * the message is destroyed). + * + * Note: If this message corresponds to multiple files in the mail + * store, (that is, multiple files contain identical message IDs), + * this function will arbitrarily return a single one of those + * filenames. See notmuch_message_get_filenames for returning the + * complete list of filenames. + */ +const char * +notmuch_message_get_filename (notmuch_message_t *message); + +/** + * Get all filenames for the email corresponding to 'message'. + * + * Returns a notmuch_filenames_t iterator listing all the filenames + * associated with 'message'. These files may not have identical + * content, but each will have the identical Message-ID. + * + * Each filename in the iterator is an absolute filename, (the initial + * component will match notmuch_database_get_path() ). + */ +notmuch_filenames_t * +notmuch_message_get_filenames (notmuch_message_t *message); + +/** + * Re-index the e-mail corresponding to 'message' using the supplied index options + * + * Returns the status of the re-index operation. (see the return + * codes documented in notmuch_database_index_file) + * + * After reindexing, the user should discard the message object passed + * in here by calling notmuch_message_destroy, since it refers to the + * original message, not to the reindexed message. + */ +notmuch_status_t +notmuch_message_reindex (notmuch_message_t *message, + notmuch_indexopts_t *indexopts); + +/** + * Message flags. + */ +typedef enum _notmuch_message_flag { + NOTMUCH_MESSAGE_FLAG_MATCH, + NOTMUCH_MESSAGE_FLAG_EXCLUDED, + + /* This message is a "ghost message", meaning it has no filenames + * or content, but we know it exists because it was referenced by + * some other message. A ghost message has only a message ID and + * thread ID. + */ + NOTMUCH_MESSAGE_FLAG_GHOST, +} notmuch_message_flag_t; + +/** + * Get a value of a flag for the email corresponding to 'message'. + */ +notmuch_bool_t +notmuch_message_get_flag (notmuch_message_t *message, + notmuch_message_flag_t flag); + +/** + * Set a value of a flag for the email corresponding to 'message'. + */ +void +notmuch_message_set_flag (notmuch_message_t *message, + notmuch_message_flag_t flag, notmuch_bool_t value); + +/** + * Get the date of 'message' as a time_t value. + * + * For the original textual representation of the Date header from the + * message call notmuch_message_get_header() with a header value of + * "date". + */ +time_t +notmuch_message_get_date (notmuch_message_t *message); + +/** + * Get the value of the specified header from 'message' as a UTF-8 string. + * + * Common headers are stored in the database when the message is + * indexed and will be returned from the database. Other headers will + * be read from the actual message file. + * + * The header name is case insensitive. + * + * The returned string belongs to the message so should not be + * modified or freed by the caller (nor should it be referenced after + * the message is destroyed). + * + * Returns an empty string ("") if the message does not contain a + * header line matching 'header'. Returns NULL if any error occurs. + */ +const char * +notmuch_message_get_header (notmuch_message_t *message, const char *header); + +/** + * Get the tags for 'message', returning a notmuch_tags_t object which + * can be used to iterate over all tags. + * + * The tags object is owned by the message and as such, will only be + * valid for as long as the message is valid, (which is until the + * query from which it derived is destroyed). + * + * Typical usage might be: + * + * notmuch_message_t *message; + * notmuch_tags_t *tags; + * const char *tag; + * + * message = notmuch_database_find_message (database, message_id); + * + * for (tags = notmuch_message_get_tags (message); + * notmuch_tags_valid (tags); + * notmuch_tags_move_to_next (tags)) + * { + * tag = notmuch_tags_get (tags); + * .... + * } + * + * notmuch_message_destroy (message); + * + * Note that there's no explicit destructor needed for the + * notmuch_tags_t object. (For consistency, we do provide a + * notmuch_tags_destroy function, but there's no good reason to call + * it if the message is about to be destroyed). + */ +notmuch_tags_t * +notmuch_message_get_tags (notmuch_message_t *message); + +/** + * The longest possible tag value. + */ +#define NOTMUCH_TAG_MAX 200 + +/** + * Add a tag to the given message. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Tag successfully added to message + * + * NOTMUCH_STATUS_NULL_POINTER: The 'tag' argument is NULL + * + * NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long + * (exceeds NOTMUCH_TAG_MAX) + * + * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only + * mode so message cannot be modified. + */ +notmuch_status_t +notmuch_message_add_tag (notmuch_message_t *message, const char *tag); + +/** + * Remove a tag from the given message. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Tag successfully removed from message + * + * NOTMUCH_STATUS_NULL_POINTER: The 'tag' argument is NULL + * + * NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long + * (exceeds NOTMUCH_TAG_MAX) + * + * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only + * mode so message cannot be modified. + */ +notmuch_status_t +notmuch_message_remove_tag (notmuch_message_t *message, const char *tag); + +/** + * Remove all tags from the given message. + * + * See notmuch_message_freeze for an example showing how to safely + * replace tag values. + * + * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only + * mode so message cannot be modified. + */ +notmuch_status_t +notmuch_message_remove_all_tags (notmuch_message_t *message); + +/** + * Add/remove tags according to maildir flags in the message filename(s). + * + * This function examines the filenames of 'message' for maildir + * flags, and adds or removes tags on 'message' as follows when these + * flags are present: + * + * Flag Action if present + * ---- ----------------- + * 'D' Adds the "draft" tag to the message + * 'F' Adds the "flagged" tag to the message + * 'P' Adds the "passed" tag to the message + * 'R' Adds the "replied" tag to the message + * 'S' Removes the "unread" tag from the message + * + * For each flag that is not present, the opposite action (add/remove) + * is performed for the corresponding tags. + * + * Flags are identified as trailing components of the filename after a + * sequence of ":2,". + * + * If there are multiple filenames associated with this message, the + * flag is considered present if it appears in one or more + * filenames. (That is, the flags from the multiple filenames are + * combined with the logical OR operator.) + * + * A client can ensure that notmuch database tags remain synchronized + * with maildir flags by calling this function after each call to + * notmuch_database_index_file. See also + * notmuch_message_tags_to_maildir_flags for synchronizing tag changes + * back to maildir flags. + */ +notmuch_status_t +notmuch_message_maildir_flags_to_tags (notmuch_message_t *message); + +/** + * return TRUE if any filename of 'message' has maildir flag 'flag', + * FALSE otherwise. + * + */ +notmuch_bool_t +notmuch_message_has_maildir_flag (notmuch_message_t *message, char flag); + +/** + * Rename message filename(s) to encode tags as maildir flags. + * + * Specifically, for each filename corresponding to this message: + * + * If the filename is not in a maildir directory, do nothing. (A + * maildir directory is determined as a directory named "new" or + * "cur".) Similarly, if the filename has invalid maildir info, + * (repeated or outof-ASCII-order flag characters after ":2,"), then + * do nothing. + * + * If the filename is in a maildir directory, rename the file so that + * its filename ends with the sequence ":2," followed by zero or more + * of the following single-character flags (in ASCII order): + * + * * flag 'D' iff the message has the "draft" tag + * * flag 'F' iff the message has the "flagged" tag + * * flag 'P' iff the message has the "passed" tag + * * flag 'R' iff the message has the "replied" tag + * * flag 'S' iff the message does not have the "unread" tag + * + * Any existing flags unmentioned in the list above will be preserved + * in the renaming. + * + * Also, if this filename is in a directory named "new", rename it to + * be within the neighboring directory named "cur". + * + * A client can ensure that maildir filename flags remain synchronized + * with notmuch database tags by calling this function after changing + * tags, (after calls to notmuch_message_add_tag, + * notmuch_message_remove_tag, or notmuch_message_freeze/ + * notmuch_message_thaw). See also notmuch_message_maildir_flags_to_tags + * for synchronizing maildir flag changes back to tags. + */ +notmuch_status_t +notmuch_message_tags_to_maildir_flags (notmuch_message_t *message); + +/** + * Freeze the current state of 'message' within the database. + * + * This means that changes to the message state, (via + * notmuch_message_add_tag, notmuch_message_remove_tag, and + * notmuch_message_remove_all_tags), will not be committed to the + * database until the message is thawed with notmuch_message_thaw. + * + * Multiple calls to freeze/thaw are valid and these calls will + * "stack". That is there must be as many calls to thaw as to freeze + * before a message is actually thawed. + * + * The ability to do freeze/thaw allows for safe transactions to + * change tag values. For example, explicitly setting a message to + * have a given set of tags might look like this: + * + * notmuch_message_freeze (message); + * + * notmuch_message_remove_all_tags (message); + * + * for (i = 0; i < NUM_TAGS; i++) + * notmuch_message_add_tag (message, tags[i]); + * + * notmuch_message_thaw (message); + * + * With freeze/thaw used like this, the message in the database is + * guaranteed to have either the full set of original tag values, or + * the full set of new tag values, but nothing in between. + * + * Imagine the example above without freeze/thaw and the operation + * somehow getting interrupted. This could result in the message being + * left with no tags if the interruption happened after + * notmuch_message_remove_all_tags but before notmuch_message_add_tag. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Message successfully frozen. + * + * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only + * mode so message cannot be modified. + */ +notmuch_status_t +notmuch_message_freeze (notmuch_message_t *message); + +/** + * Thaw the current 'message', synchronizing any changes that may have + * occurred while 'message' was frozen into the notmuch database. + * + * See notmuch_message_freeze for an example of how to use this + * function to safely provide tag changes. + * + * Multiple calls to freeze/thaw are valid and these calls with + * "stack". That is there must be as many calls to thaw as to freeze + * before a message is actually thawed. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Message successfully thawed, (or at least + * its frozen count has successfully been reduced by 1). + * + * NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: An attempt was made to thaw + * an unfrozen message. That is, there have been an unbalanced + * number of calls to notmuch_message_freeze and + * notmuch_message_thaw. + */ +notmuch_status_t +notmuch_message_thaw (notmuch_message_t *message); + +/** + * Destroy a notmuch_message_t object. + * + * It can be useful to call this function in the case of a single + * query object with many messages in the result, (such as iterating + * over the entire database). Otherwise, it's fine to never call this + * function and there will still be no memory leaks. (The memory from + * the messages get reclaimed when the containing query is destroyed.) + */ +void +notmuch_message_destroy (notmuch_message_t *message); + +/** + * @name Message Properties + * + * This interface provides the ability to attach arbitrary (key,value) + * string pairs to a message, to remove such pairs, and to iterate + * over them. The caller should take some care as to what keys they + * add or delete values for, as other subsystems or extensions may + * depend on these properties. + * + * Please see notmuch-properties(7) for more details about specific + * properties and conventions around their use. + * + */ +/**@{*/ +/** + * Retrieve the value for a single property key + * + * *value* is set to a string owned by the message or NULL if there is + * no such key. In the case of multiple values for the given key, the + * first one is retrieved. + * + * @returns + * - NOTMUCH_STATUS_NULL_POINTER: *value* may not be NULL. + * - NOTMUCH_STATUS_SUCCESS: No error occurred. + * @since libnotmuch 4.4 (notmuch 0.23) + */ +notmuch_status_t +notmuch_message_get_property (notmuch_message_t *message, const char *key, const char **value); + +/** + * Add a (key,value) pair to a message + * + * @returns + * - NOTMUCH_STATUS_ILLEGAL_ARGUMENT: *key* may not contain an '=' character. + * - NOTMUCH_STATUS_NULL_POINTER: Neither *key* nor *value* may be NULL. + * - NOTMUCH_STATUS_SUCCESS: No error occurred. + * @since libnotmuch 4.4 (notmuch 0.23) + */ +notmuch_status_t +notmuch_message_add_property (notmuch_message_t *message, const char *key, const char *value); + +/** + * Remove a (key,value) pair from a message. + * + * It is not an error to remove a non-existant (key,value) pair + * + * @returns + * - NOTMUCH_STATUS_ILLEGAL_ARGUMENT: *key* may not contain an '=' character. + * - NOTMUCH_STATUS_NULL_POINTER: Neither *key* nor *value* may be NULL. + * - NOTMUCH_STATUS_SUCCESS: No error occurred. + * @since libnotmuch 4.4 (notmuch 0.23) + */ +notmuch_status_t +notmuch_message_remove_property (notmuch_message_t *message, const char *key, const char *value); + +/** + * Remove all (key,value) pairs from the given message. + * + * @param[in,out] message message to operate on. + * @param[in] key key to delete properties for. If NULL, delete + * properties for all keys + * @returns + * - NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in + * read-only mode so message cannot be modified. + * - NOTMUCH_STATUS_SUCCESS: No error occurred. + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +notmuch_status_t +notmuch_message_remove_all_properties (notmuch_message_t *message, const char *key); + +/** + * Remove all (prefix*,value) pairs from the given message + * + * @param[in,out] message message to operate on. + * @param[in] prefix delete properties with keys that start with prefix. + * If NULL, delete all properties + * @returns + * - NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in + * read-only mode so message cannot be modified. + * - NOTMUCH_STATUS_SUCCESS: No error occurred. + * + * @since libnotmuch 5.1 (notmuch 0.26) + */ +notmuch_status_t +notmuch_message_remove_all_properties_with_prefix (notmuch_message_t *message, const char *prefix); + +/** + * Opaque message property iterator + */ +typedef struct _notmuch_string_map_iterator notmuch_message_properties_t; + +/** + * Get the properties for *message*, returning a + * notmuch_message_properties_t object which can be used to iterate + * over all properties. + * + * The notmuch_message_properties_t object is owned by the message and + * as such, will only be valid for as long as the message is valid, + * (which is until the query from which it derived is destroyed). + * + * @param[in] message The message to examine + * @param[in] key key or key prefix + * @param[in] exact if TRUE, require exact match with key. Otherwise + * treat as prefix. + * + * Typical usage might be: + * + * notmuch_message_properties_t *list; + * + * for (list = notmuch_message_get_properties (message, "testkey1", TRUE); + * notmuch_message_properties_valid (list); notmuch_message_properties_move_to_next (list)) { + * printf("%s\n", notmuch_message_properties_value(list)); + * } + * + * notmuch_message_properties_destroy (list); + * + * Note that there's no explicit destructor needed for the + * notmuch_message_properties_t object. (For consistency, we do + * provide a notmuch_message_properities_destroy function, but there's + * no good reason to call it if the message is about to be destroyed). + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +notmuch_message_properties_t * +notmuch_message_get_properties (notmuch_message_t *message, const char *key, notmuch_bool_t exact); + +/** + * Return the number of properties named "key" belonging to the specific message. + * + * @param[in] message The message to examine + * @param[in] key key to count + * @param[out] count The number of matching properties associated with this message. + * + * @returns + * + * NOTMUCH_STATUS_SUCCESS: successful count, possibly some other error. + * + * @since libnotmuch 5.2 (notmuch 0.27) + */ +notmuch_status_t +notmuch_message_count_properties (notmuch_message_t *message, const char *key, unsigned int *count); + +/** + * Is the given *properties* iterator pointing at a valid (key,value) + * pair. + * + * When this function returns TRUE, + * notmuch_message_properties_{key,value} will return a valid string, + * and notmuch_message_properties_move_to_next will do what it + * says. Whereas when this function returns FALSE, calling any of + * these functions results in undefined behaviour. + * + * See the documentation of notmuch_message_get_properties for example + * code showing how to iterate over a notmuch_message_properties_t + * object. + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +notmuch_bool_t +notmuch_message_properties_valid (notmuch_message_properties_t *properties); + +/** + * Move the *properties* iterator to the next (key,value) pair + * + * If *properties* is already pointing at the last pair then the iterator + * will be moved to a point just beyond that last pair, (where + * notmuch_message_properties_valid will return FALSE). + * + * See the documentation of notmuch_message_get_properties for example + * code showing how to iterate over a notmuch_message_properties_t object. + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +void +notmuch_message_properties_move_to_next (notmuch_message_properties_t *properties); + +/** + * Return the key from the current (key,value) pair. + * + * this could be useful if iterating for a prefix + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +const char * +notmuch_message_properties_key (notmuch_message_properties_t *properties); + +/** + * Return the value from the current (key,value) pair. + * + * This could be useful if iterating for a prefix. + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +const char * +notmuch_message_properties_value (notmuch_message_properties_t *properties); + + +/** + * Destroy a notmuch_message_properties_t object. + * + * It's not strictly necessary to call this function. All memory from + * the notmuch_message_properties_t object will be reclaimed when the + * containing message object is destroyed. + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +void +notmuch_message_properties_destroy (notmuch_message_properties_t *properties); + +/**@}*/ + +/** + * Is the given 'tags' iterator pointing at a valid tag. + * + * When this function returns TRUE, notmuch_tags_get will return a + * valid string. Whereas when this function returns FALSE, + * notmuch_tags_get will return NULL. + * + * See the documentation of notmuch_message_get_tags for example code + * showing how to iterate over a notmuch_tags_t object. + */ +notmuch_bool_t +notmuch_tags_valid (notmuch_tags_t *tags); + +/** + * Get the current tag from 'tags' as a string. + * + * Note: The returned string belongs to 'tags' and has a lifetime + * identical to it (and the query to which it ultimately belongs). + * + * See the documentation of notmuch_message_get_tags for example code + * showing how to iterate over a notmuch_tags_t object. + */ +const char * +notmuch_tags_get (notmuch_tags_t *tags); + +/** + * Move the 'tags' iterator to the next tag. + * + * If 'tags' is already pointing at the last tag then the iterator + * will be moved to a point just beyond that last tag, (where + * notmuch_tags_valid will return FALSE and notmuch_tags_get will + * return NULL). + * + * See the documentation of notmuch_message_get_tags for example code + * showing how to iterate over a notmuch_tags_t object. + */ +void +notmuch_tags_move_to_next (notmuch_tags_t *tags); + +/** + * Destroy a notmuch_tags_t object. + * + * It's not strictly necessary to call this function. All memory from + * the notmuch_tags_t object will be reclaimed when the containing + * message or query objects are destroyed. + */ +void +notmuch_tags_destroy (notmuch_tags_t *tags); + +/** + * Store an mtime within the database for 'directory'. + * + * The 'directory' should be an object retrieved from the database + * with notmuch_database_get_directory for a particular path. + * + * The intention is for the caller to use the mtime to allow efficient + * identification of new messages to be added to the database. The + * recommended usage is as follows: + * + * o Read the mtime of a directory from the filesystem + * + * o Call index_file for all mail files in the directory + * + * o Call notmuch_directory_set_mtime with the mtime read from the + * filesystem. + * + * Then, when wanting to check for updates to the directory in the + * future, the client can call notmuch_directory_get_mtime and know + * that it only needs to add files if the mtime of the directory and + * files are newer than the stored timestamp. + * + * Note: The notmuch_directory_get_mtime function does not allow the + * caller to distinguish a timestamp of 0 from a non-existent + * timestamp. So don't store a timestamp of 0 unless you are + * comfortable with that. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: mtime successfully stored in database. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception + * occurred, mtime not stored. + * + * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only + * mode so directory mtime cannot be modified. + */ +notmuch_status_t +notmuch_directory_set_mtime (notmuch_directory_t *directory, + time_t mtime); + +/** + * Get the mtime of a directory, (as previously stored with + * notmuch_directory_set_mtime). + * + * Returns 0 if no mtime has previously been stored for this + * directory. + */ +time_t +notmuch_directory_get_mtime (notmuch_directory_t *directory); + +/** + * Get a notmuch_filenames_t iterator listing all the filenames of + * messages in the database within the given directory. + * + * The returned filenames will be the basename-entries only (not + * complete paths). + */ +notmuch_filenames_t * +notmuch_directory_get_child_files (notmuch_directory_t *directory); + +/** + * Get a notmuch_filenames_t iterator listing all the filenames of + * sub-directories in the database within the given directory. + * + * The returned filenames will be the basename-entries only (not + * complete paths). + */ +notmuch_filenames_t * +notmuch_directory_get_child_directories (notmuch_directory_t *directory); + +/** + * Delete directory document from the database, and destroy the + * notmuch_directory_t object. Assumes any child directories and files + * have been deleted by the caller. + * + * @since libnotmuch 4.3 (notmuch 0.21) + */ +notmuch_status_t +notmuch_directory_delete (notmuch_directory_t *directory); + +/** + * Destroy a notmuch_directory_t object. + */ +void +notmuch_directory_destroy (notmuch_directory_t *directory); + +/** + * Is the given 'filenames' iterator pointing at a valid filename. + * + * When this function returns TRUE, notmuch_filenames_get will return + * a valid string. Whereas when this function returns FALSE, + * notmuch_filenames_get will return NULL. + * + * It is acceptable to pass NULL for 'filenames', in which case this + * function will always return FALSE. + */ +notmuch_bool_t +notmuch_filenames_valid (notmuch_filenames_t *filenames); + +/** + * Get the current filename from 'filenames' as a string. + * + * Note: The returned string belongs to 'filenames' and has a lifetime + * identical to it (and the directory to which it ultimately belongs). + * + * It is acceptable to pass NULL for 'filenames', in which case this + * function will always return NULL. + */ +const char * +notmuch_filenames_get (notmuch_filenames_t *filenames); + +/** + * Move the 'filenames' iterator to the next filename. + * + * If 'filenames' is already pointing at the last filename then the + * iterator will be moved to a point just beyond that last filename, + * (where notmuch_filenames_valid will return FALSE and + * notmuch_filenames_get will return NULL). + * + * It is acceptable to pass NULL for 'filenames', in which case this + * function will do nothing. + */ +void +notmuch_filenames_move_to_next (notmuch_filenames_t *filenames); + +/** + * Destroy a notmuch_filenames_t object. + * + * It's not strictly necessary to call this function. All memory from + * the notmuch_filenames_t object will be reclaimed when the + * containing directory object is destroyed. + * + * It is acceptable to pass NULL for 'filenames', in which case this + * function will do nothing. + */ +void +notmuch_filenames_destroy (notmuch_filenames_t *filenames); + + +/** + * set config 'key' to 'value' + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +notmuch_status_t +notmuch_database_set_config (notmuch_database_t *db, const char *key, const char *value); + +/** + * retrieve config item 'key', assign to 'value' + * + * keys which have not been previously set with n_d_set_config will + * return an empty string. + * + * return value is allocated by malloc and should be freed by the + * caller. + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +notmuch_status_t +notmuch_database_get_config (notmuch_database_t *db, const char *key, char **value); + +/** + * Create an iterator for all config items with keys matching a given prefix + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +notmuch_status_t +notmuch_database_get_config_list (notmuch_database_t *db, const char *prefix, notmuch_config_list_t **out); + +/** + * Is 'config_list' iterator valid (i.e. _key, _value, _move_to_next can be called). + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +notmuch_bool_t +notmuch_config_list_valid (notmuch_config_list_t *config_list); + +/** + * return key for current config pair + * + * return value is owned by the iterator, and will be destroyed by the + * next call to notmuch_config_list_key or notmuch_config_list_destroy. + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +const char * +notmuch_config_list_key (notmuch_config_list_t *config_list); + +/** + * return 'value' for current config pair + * + * return value is owned by the iterator, and will be destroyed by the + * next call to notmuch_config_list_value or notmuch config_list_destroy + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +const char * +notmuch_config_list_value (notmuch_config_list_t *config_list); + + +/** + * move 'config_list' iterator to the next pair + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +void +notmuch_config_list_move_to_next (notmuch_config_list_t *config_list); + +/** + * free any resources held by 'config_list' + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +void +notmuch_config_list_destroy (notmuch_config_list_t *config_list); + + +/** + * get the current default indexing options for a given database. + * + * This object will survive until the database itself is destroyed, + * but the caller may also release it earlier with + * notmuch_indexopts_destroy. + * + * This object represents a set of options on how a message can be + * added to the index. At the moment it is a featureless stub. + * + * @since libnotmuch 5.1 (notmuch 0.26) + */ +notmuch_indexopts_t * +notmuch_database_get_default_indexopts (notmuch_database_t *db); + +/** + * Stating a policy about how to decrypt messages. + * + * See index.decrypt in notmuch-config(1) for more details. + */ +typedef enum { + NOTMUCH_DECRYPT_FALSE, + NOTMUCH_DECRYPT_TRUE, + NOTMUCH_DECRYPT_AUTO, + NOTMUCH_DECRYPT_NOSTASH, +} notmuch_decryption_policy_t; + +/** + * Specify whether to decrypt encrypted parts while indexing. + * + * Be aware that the index is likely sufficient to reconstruct the + * cleartext of the message itself, so please ensure that the notmuch + * message index is adequately protected. DO NOT SET THIS FLAG TO TRUE + * without considering the security of your index. + * + * @since libnotmuch 5.1 (notmuch 0.26) + */ +notmuch_status_t +notmuch_indexopts_set_decrypt_policy (notmuch_indexopts_t *indexopts, + notmuch_decryption_policy_t decrypt_policy); + +/** + * Return whether to decrypt encrypted parts while indexing. + * see notmuch_indexopts_set_decrypt_policy. + * + * @since libnotmuch 5.1 (notmuch 0.26) + */ +notmuch_decryption_policy_t +notmuch_indexopts_get_decrypt_policy (const notmuch_indexopts_t *indexopts); + +/** + * Destroy a notmuch_indexopts_t object. + * + * @since libnotmuch 5.1 (notmuch 0.26) + */ +void +notmuch_indexopts_destroy (notmuch_indexopts_t *options); + + +/** + * interrogate the library for compile time features + * + * @since libnotmuch 4.4 (notmuch 0.23) + */ +notmuch_bool_t +notmuch_built_with (const char *name); +/* @} */ + +#pragma GCC visibility pop + +NOTMUCH_END_DECLS + +#endif diff --git a/sample-config b/sample-config index 0bb8ad9e..97a78078 100644 --- a/sample-config +++ b/sample-config @@ -39,6 +39,19 @@ #display_name = "Name Name" #subscribed_folders = ["INBOX", "INBOX/Sent", "INBOX/Drafts", "INBOX/Junk"] +# Setting up an account for an already existing notmuch database +#[accounts.notmuch] +#root_folder = "/path/to/folder" # where .notmuch/ directory is located +#format = "notmuch" +#index_style = "conversations" +#identity="username@server.tld" +#display_name = "Name Name" +# # notmuch folders are virtual, they are defined by their alias and the notmuch query that corresponds to their content. +# [accounts.notmuch.folders] +# "INBOX" = { query="tag:inbox", subscribe = true } +# "Drafts" = { query="tag:draft", subscribe = true } +# "Sent" = { query="from:username@server.tld from:username2@server.tld", subscribe = true } +# #[pager] #filter = "/usr/bin/pygmentize" #pager_context = 0 # default, optional