Skip to content

Commit

Permalink
Add open_with_config
Browse files Browse the repository at this point in the history
The other open functions have since been deprecated in the C API, and
the current implementation of `open` in notmuch-rs doesn't support
passing null pointers. Adding `open_with_config` and allowing it to
accept `Option` types fixes this problem in a backwards-compatible way.

I would have preferred to add a `String` to `NotmuchError` instead of
creating `NotmuchVerboseError`, but I didn't want to break
compatibility.
  • Loading branch information
elizagamedev committed May 1, 2022
1 parent c8aaed2 commit 3071c52
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 6 deletions.
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,27 @@ extern crate notmuch;
```rust
extern crate notmuch;


fn main() {

let mut mail_path = std::env::home_dir().unwrap();
mail_path.push(".mail");

let db = notmuch::Database::open(&mail_path, notmuch::DatabaseMode::ReadOnly).unwrap();
let mut config_path = std::env::home_dir().unwrap();
config_path.push(".config/custom-notmuch-config-path");

let db = notmuch::Database::open_with_config(
&mail_path,
notmuch::DatabaseMode::ReadOnly,
&config_path,
None,
)
.unwrap();
let query = db.create_query("").unwrap();
let mut threads = query.search_threads().unwrap();

for thread in threads {
println!("thread {:?} {:?}", thread.subject(), thread.authors());
}
}

```

## Concurrency
Expand Down
54 changes: 53 additions & 1 deletion src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ impl Database {
})
}

#[deprecated = "Replaced with `open_with_config`"]
pub fn open<P>(path: P, mode: DatabaseMode) -> Result<Self>
where
P: AsRef<Path>,
Expand All @@ -87,6 +88,55 @@ impl Database {
})
}

pub fn open_with_config<DP, CP>(
database_path: Option<DP>,
mode: DatabaseMode,
config_path: Option<CP>,
profile: Option<&str>,
) -> Result<Self>
where
DP: AsRef<Path>,
CP: AsRef<Path>,
{
let database_path_str =
database_path.map(|p| CString::new(p.as_ref().to_str().unwrap()).unwrap());
let database_path_ptr = database_path_str
.as_ref()
.map(|p| p.as_ptr())
.unwrap_or_else(|| ptr::null());

let config_path_str =
config_path.map(|p| CString::new(p.as_ref().to_str().unwrap()).unwrap());
let config_path_ptr = config_path_str
.as_ref()
.map(|p| p.as_ptr())
.unwrap_or_else(|| ptr::null());

let profile_str = profile.map(|p| CString::new(p).unwrap());
let profile_ptr = profile_str
.as_ref()
.map(|p| p.as_ptr())
.unwrap_or_else(|| ptr::null());

let mut db = ptr::null_mut();
let mut error_message = ptr::null_mut();
unsafe {
ffi::notmuch_database_open_with_config(
database_path_ptr,
mode.into(),
config_path_ptr,
profile_ptr,
&mut db,
&mut error_message,
)
}
.as_verbose_result(error_message)?;

Ok(Database {
ptr: Rc::new(DatabasePtr(db)),
})
}

pub fn close(&self) -> Result<()> {
unsafe { ffi::notmuch_database_close(self.ptr.0) }.as_result()?;

Expand Down Expand Up @@ -360,7 +410,9 @@ pub struct AtomicOperation {
impl AtomicOperation {
pub fn new(database: &Database) -> Result<Self> {
database.begin_atomic()?;
Ok(AtomicOperation { database: database.clone() })
Ok(AtomicOperation {
database: database.clone(),
})
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub type Result<T> = result::Result<T, Error>;
pub enum Error {
IoError(io::Error),
NotmuchError(ffi::Status),
NotmuchVerboseError(ffi::Status, String),
UnspecifiedError,
}

Expand All @@ -17,6 +18,7 @@ impl fmt::Display for Error {
match self {
Error::IoError(e) => e.fmt(f),
Error::NotmuchError(e) => e.fmt(f),
Error::NotmuchVerboseError(e, msg) => write!(f, "{} {}", e, msg),
Error::UnspecifiedError => write!(f, "Generic notmuch error"),
}
}
Expand All @@ -27,6 +29,7 @@ impl error::Error for Error {
match &self {
Error::IoError(e) => Some(e),
Error::NotmuchError(e) => Some(e),
Error::NotmuchVerboseError(e, _) => Some(e),
Error::UnspecifiedError => None,
}
}
Expand Down
129 changes: 128 additions & 1 deletion src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
use libc::{c_char, c_double, c_int, c_uint, c_ulong, c_void, time_t};

use error::{Error, Result};
use std::{error, fmt, str};
use std::borrow::Cow;
use std::ffi::CStr;
use std::{error, fmt, ptr, str};
use utils::ToStr;

notmuch_enum! {
Expand Down Expand Up @@ -60,6 +61,30 @@ impl notmuch_status_t {
Err(Error::NotmuchError(Status::from(self)))
}
}

pub fn as_verbose_result(self, error_message_cstr: *mut c_char) -> Result<()> {
let error_message = if error_message_cstr == ptr::null_mut() {
None
} else {
unsafe {
let msg = Some(
CStr::from_ptr(error_message_cstr)
.to_string_lossy()
.to_string(),
);
libc::free(error_message_cstr as *mut c_void);
msg
}
};
if self.is_ok() {
Ok(())
} else {
Err(Error::NotmuchVerboseError(
Status::from(self),
error_message.unwrap(),
))
}
}
}

impl ToStr for Status {
Expand Down Expand Up @@ -272,6 +297,108 @@ extern "C" {
error_message: *mut *mut c_char,
) -> notmuch_status_t;

/// Open an existing notmuch database located at `database_path`, using
/// configuration in `config_path`.
///
/// * `database_path`: Path to existing database.
///
/// A notmuch database is a Xapian database containing appropriate
/// metadata.
///
/// The database should have been created at some time in the past, (not
/// necessarily by this process), by calling `notmuch_database_create`.
///
/// If `database_path` is `NULL`, use the location specified
///
/// * in the environment variable `NOTMUCH_DATABASE`, if non-empty
///
/// * in a configuration file, located as described under 'config_path'
///
/// * by `$XDG_DATA_HOME`/notmuch/`$PROFILE` where `XDG_DATA_HOME`
/// defaults to "$HOME/.local/share" and `PROFILE` as as discussed in
/// 'profile'
///
/// If `database_path` is non-`NULL`, but does not appear to be a Xapian
/// database, check for a directory '.notmuch/xapian' below
/// `database_path` (this is the behavior of
/// `notmuch_database_open_verbose` pre-0.32).
///
/// * `mode`: Mode to open database. Use one of
/// `notmuch_database_mode_t::READ_WRITE` or
/// `notmuch_database_mode_t::READ_ONLY`.
///
/// * `config_path`: Path to config file.
///
/// Config file is key-value, with mandatory sections. See
/// `notmuch-config(5)` for more information. The key-value pair
/// overrides the corresponding configuration data stored in the
/// database (see `notmuch_database_get_config`).
///
/// If `config_path` is `NULL` use the path specified
///
/// * in environment variable `NOTMUCH_CONFIG`, if non-empty
///
/// * by `XDG_CONFIG_HOME`/notmuch/ where `XDG_CONFIG_HOME` defaults to
/// "`$HOME`/.config".
///
/// * by `$HOME`/.notmuch-config
///
/// If `config_path` is `""` (empty string) then do not open any
/// configuration file.
///
/// * `profile`: Name of profile (configuration/database variant).
///
/// If non-`NULL`, append to the directory / file path determined for
/// `config_path` and `database_path`.
///
/// If `NULL` then use
///
/// * environment variable `NOTMUCH_PROFILE` if defined,
///
/// * otherwise `"default"` for directories and `""` (empty string) for
/// paths.
///
/// * `database`: Pointer to database object. May not be `NULL`.
///
/// 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`.
///
/// * `error_message`: If non-`NULL`, store error message from opening the
/// database.
///
/// Any such message is allocated by `malloc(3)` and should be freed by
/// the caller.
///
/// Return Value:
///
/// * `notmuch_status_t::SUCCESS`: Successfully opened the database.
///
/// * `notmuch_status_t::NULL_POINTER`: The given `database` argument is
/// `NULL`.
///
/// * `notmuch_status_t::NO_CONFIG`: No config file was found. Fatal.
///
/// * `notmuch_status_t::OUT_OF_MEMORY`: Out of memory.
///
/// * `notmuch_status_t::FILE_ERROR`: An error occurred trying to open the
/// database or config file (such as permission denied, or file not
/// found, etc.), or the database version is unknown.
///
/// * `notmuch_status_t::XAPIAN_EXCEPTION`: A Xapian exception occurred.
///
/// Since libnotmuch 5.4 (notmuch 0.32)
pub fn notmuch_database_open_with_config(
database_path: *const c_char,
mode: notmuch_database_mode_t,
config_path: *const c_char,
profile: *const c_char,
database: *mut *mut notmuch_database_t,
error_message: *mut *mut c_char,
) -> notmuch_status_t;

/// Retrieve last status string for given database.
pub fn notmuch_database_status_string(notmuch: *mut notmuch_database_t) -> *const c_char;

Expand Down

0 comments on commit 3071c52

Please sign in to comment.