summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/example.c2
-rw-r--r--src/ffi.rs128
-rw-r--r--src/lib.rs60
-rw-r--r--src/sequoia.h79
4 files changed, 214 insertions, 55 deletions
diff --git a/examples/example.c b/examples/example.c
index 22bace0f..5b087c15 100644
--- a/examples/example.c
+++ b/examples/example.c
@@ -22,7 +22,7 @@ main (int argc, char **argv)
if (argc != 2)
error (1, 0, "Usage: %s <file>", argv[0]);
- ctx = sq_context_new("org.sequoia-pgp.example", NULL, NULL);
+ ctx = sq_context_new("org.sequoia-pgp.example");
if (ctx == NULL)
error (1, 0, "Initializing sequoia failed.");
diff --git a/src/ffi.rs b/src/ffi.rs
index 1a315684..1e1af9b3 100644
--- a/src/ffi.rs
+++ b/src/ffi.rs
@@ -9,51 +9,33 @@ use std::str;
use keys::TPK;
use openpgp;
use openpgp::types::KeyId;
-use super::Context;
+use super::{Config, Context};
-/// Create a context object.
+/* sequoia::Context. */
+
+/// Creates a Context with reasonable defaults.
///
-/// If `home` is not `NULL`, it is used as directory containing shared
-/// state and rendezvous nodes. If `lib` is not `NULL`, it is used as
-/// directory containing backend servers. If either argument is
-/// `NULL`, a reasonable default is used.
+/// `domain` should uniquely identify your application, it is strongly
+/// suggested to use a reversed fully qualified domain name that is
+/// associated with your application. `domain` must not be `NULL`.
///
/// Returns `NULL` on errors.
#[no_mangle]
-pub extern "system" fn sq_context_new(domain: *const c_char,
- home: *const c_char,
- lib: *const c_char) -> *mut Context {
+pub extern "system" fn sq_context_new(domain: *const c_char)
+ -> *mut Context {
+ assert!(! domain.is_null());
let domain = unsafe {
- if domain.is_null() { None } else { Some(CStr::from_ptr(domain)) }
- };
- let home = unsafe {
- if home.is_null() { None } else { Some(CStr::from_ptr(home)) }
+ CStr::from_ptr(domain).to_string_lossy()
};
- let lib = unsafe {
- if lib.is_null() { None } else { Some(CStr::from_ptr(lib)) }
- };
-
- if domain.is_none() {
- return ptr::null_mut();
- }
- let mut pre = Context::new(&domain.unwrap().to_string_lossy());
-
- if let Some(home) = home {
- pre = pre.home(home.to_string_lossy().as_ref());
- }
- if let Some(lib) = lib {
- pre = pre.lib(lib.to_string_lossy().as_ref());
- }
-
- if let Ok(context) = pre.finalize() {
+ if let Ok(context) = Context::new(&domain) {
Box::into_raw(Box::new(context))
} else {
ptr::null_mut()
}
}
-/// Free a context.
+/// Frees a context.
#[no_mangle]
pub extern "system" fn sq_context_free(context: *mut Context) {
unsafe {
@@ -61,7 +43,91 @@ pub extern "system" fn sq_context_free(context: *mut Context) {
}
}
+/// Creates a Context that can be configured.
+///
+/// `domain` should uniquely identify your application, it is strongly
+/// suggested to use a reversed fully qualified domain name that is
+/// associated with your application. `domain` must not be `NULL`.
+///
+/// The configuration is seeded like in `sq_context_new`, but can be
+/// modified. A configuration has to be finalized using
+/// `sq_config_build()` in order to turn it into a Context.
+#[no_mangle]
+pub extern "system" fn sq_context_configure(domain: *const c_char)
+ -> *mut Config {
+ assert!(! domain.is_null());
+ let domain = unsafe {
+ CStr::from_ptr(domain).to_string_lossy()
+ };
+
+ Box::into_raw(Box::new(Context::configure(&domain)))
+}
+
+/// Returns the domain of the context.
+#[no_mangle]
+pub extern "system" fn sq_context_domain(ctx: Option<&Context>) -> *const c_char {
+ assert!(ctx.is_some());
+ ctx.unwrap().domain().as_bytes().as_ptr() as *const c_char
+}
+
+/// Returns the directory containing shared state.
+#[no_mangle]
+pub extern "system" fn sq_context_home(ctx: Option<&Context>) -> *const c_char {
+ assert!(ctx.is_some());
+ ctx.unwrap().home().to_string_lossy().as_ptr() as *const c_char
+}
+
+/// Returns the directory containing backend servers.
+#[no_mangle]
+pub extern "system" fn sq_context_lib(ctx: Option<&Context>) -> *const c_char {
+ assert!(ctx.is_some());
+ ctx.unwrap().lib().to_string_lossy().as_bytes().as_ptr() as *const c_char
+}
+
+/* sequoia::Config. */
+
+/// Finalizes the configuration and return a `Context`.
+///
+/// Consumes `cfg`. Returns `NULL` on errors.
+#[no_mangle]
+pub extern "system" fn sq_config_build(cfg: Option<&mut Config>)
+ -> *mut Context {
+ assert!(cfg.is_some());
+ let cfg = unsafe { Box::from_raw(cfg.unwrap()) };
+
+ if let Ok(context) = cfg.build() {
+ Box::into_raw(Box::new(context))
+ } else {
+ ptr::null_mut()
+ }
+}
+
+/// Sets the directory containing shared state.
+#[no_mangle]
+pub extern "system" fn sq_config_home(cfg: Option<&mut Config>,
+ home: *const c_char) {
+ assert!(cfg.is_some());
+ assert!(! home.is_null());
+ let home = unsafe {
+ CStr::from_ptr(home).to_string_lossy()
+ };
+ cfg.unwrap().set_home(home.as_ref())
+}
+
+/// Set the directory containing backend servers.
+#[no_mangle]
+pub extern "system" fn sq_config_lib(cfg: Option<&mut Config>,
+ lib: *const c_char) {
+ assert!(cfg.is_some());
+ assert!(! lib.is_null());
+ let lib = unsafe {
+ CStr::from_ptr(lib).to_string_lossy()
+ };
+ cfg.unwrap().set_lib(&lib.as_ref())
+}
+
/* openpgp::types. */
+
/// Returns a KeyID with the given `id`.
#[no_mangle]
pub extern "system" fn sq_keyid_new(id: uint64_t) -> *mut KeyId {
diff --git a/src/lib.rs b/src/lib.rs
index 97315726..e3890089 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -28,7 +28,7 @@ use std::path::{Path, PathBuf};
///
/// ```
/// # use sequoia::Context;
-/// let c = Context::new("org.example.webmail").finalize().unwrap();
+/// let c = Context::new("org.example.webmail").unwrap();
/// ```
pub struct Context {
domain: String,
@@ -42,16 +42,26 @@ fn prefix() -> PathBuf {
}
impl Context {
- /// Creates a `Pre(Context)` with reasonable defaults.
+ /// Creates a Context with reasonable defaults.
+ ///
+ /// `domain` should uniquely identify your application, it is
+ /// strongly suggested to use a reversed fully qualified domain
+ /// name that is associated with your application.
+ pub fn new(domain: &str) -> io::Result<Self> {
+ Self::configure(domain).build()
+ }
+
+ /// Creates a Context that can be configured.
///
/// `domain` should uniquely identify your application, it is
/// strongly suggested to use a reversed fully qualified domain
/// name that is associated with your application.
///
- /// `Pre(Context)`s can be modified, and have to be finalized in
- /// order to turn them into a Context.
- pub fn new(domain: &str) -> Pre {
- Pre(Context {
+ /// The configuration is seeded like in `Context::new`, but can be
+ /// modified. A configuration has to be finalized using
+ /// `.build()` in order to turn it into a Context.
+ pub fn configure(domain: &str) -> Config {
+ Config(Context {
domain: String::from(domain),
home: env::home_dir().unwrap_or(env::temp_dir())
.join(".sequoia"),
@@ -59,44 +69,52 @@ impl Context {
})
}
- /// Return the directory containing backend servers.
+ /// Returns the domain of the context.
pub fn domain(&self) -> &str {
&self.domain
}
- /// Return the directory containing shared state and rendezvous
- /// nodes.
+ /// Returns the directory containing shared state.
pub fn home(&self) -> &Path {
&self.home
}
- /// Return the directory containing backend servers.
+ /// Returns the directory containing backend servers.
pub fn lib(&self) -> &Path {
&self.lib
}
}
-/// A `Pre(Context)` is a context object that can be modified.
-pub struct Pre(Context);
+/// Represents a `Context` configuration.
+pub struct Config(Context);
-impl Pre {
- /// Finalize the configuration and return a `Context`.
- pub fn finalize(self) -> io::Result<Context> {
+impl Config {
+ /// Finalizes the configuration and return a `Context`.
+ pub fn build(self) -> io::Result<Context> {
let c = self.0;
fs::create_dir_all(c.home())?;
Ok(c)
}
- /// Set the directory containing shared state and rendezvous
- /// nodes.
- pub fn home<P: AsRef<Path>>(mut self, new: P) -> Self {
- self.0.home = PathBuf::new().join(new);
+ /// Sets the directory containing shared state.
+ pub fn home<P: AsRef<Path>>(mut self, home: P) -> Self {
+ self.set_home(home);
self
}
+ /// Sets the directory containing shared state.
+ pub fn set_home<P: AsRef<Path>>(&mut self, home: P) {
+ self.0.home = PathBuf::new().join(home);
+ }
+
/// Set the directory containing backend servers.
- pub fn lib<P: AsRef<Path>>(mut self, new: P) -> Self {
- self.0.lib = PathBuf::new().join(new);
+ pub fn lib<P: AsRef<Path>>(mut self, lib: P) -> Self {
+ self.set_lib(lib);
self
}
+
+ /// Sets the directory containing shared state.
+ pub fn set_lib<P: AsRef<Path>>(&mut self, lib: P) {
+ self.0.lib = PathBuf::new().join(lib);
+ }
}
diff --git a/src/sequoia.h b/src/sequoia.h
index 51ac441b..1b7015b5 100644
--- a/src/sequoia.h
+++ b/src/sequoia.h
@@ -1,13 +1,88 @@
#ifndef SEQUOIA_H
#define SEQUOIA_H
+#include <stddef.h>
#include <stdint.h>
+/*/
+/// A `&Context` is required for many operations.
+///
+/// # Example
+///
+/// ```c
+/// struct sq_context *ctx sq_context_new("org.sequoia-pgp.example");
+/// if (ctx == 0) { ... }
+/// ```
+/*/
struct sq_context;
-struct sq_context *sq_context_new(const char *domain, const char *home,
- const char *lib);
+
+/*/
+/*/
+struct sq_config;
+
+/*/
+/// Creates a Context with reasonable defaults.
+///
+/// `domain` should uniquely identify your application, it is strongly
+/// suggested to use a reversed fully qualified domain name that is
+/// associated with your application. `domain` must not be `NULL`.
+///
+/// Returns `NULL` on errors.
+/*/
+struct sq_context *sq_context_new(const char *domain);
+
+/*/
+/// Frees a context.
+/*/
void sq_context_free(struct sq_context *context);
+/*/
+/// Creates a Context that can be configured.
+///
+/// `domain` should uniquely identify your application, it is strongly
+/// suggested to use a reversed fully qualified domain name that is
+/// associated with your application. `domain` must not be `NULL`.
+///
+/// The configuration is seeded like in `sq_context_new`, but can be
+/// modified. A configuration has to be finalized using
+/// `sq_config_build()` in order to turn it into a Context.
+/*/
+struct sq_config *sq_context_configure(const char *domain);
+
+/*/
+/// Returns the domain of the context.
+/*/
+const char *sq_context_domain(const struct sq_context *ctx);
+
+/*/
+/// Returns the directory containing shared state.
+/*/
+const char *sq_context_home(const struct sq_context *ctx);
+
+/*/
+/// Returns the directory containing backend servers.
+/*/
+const char *sq_context_lib(const struct sq_context *ctx);
+
+/* sequoia::Config. */
+
+/*/
+/// Finalizes the configuration and return a `Context`.
+///
+/// Consumes `cfg`. Returns `NULL` on errors.
+/*/
+struct sq_context *sq_config_build(struct sq_config *cfg);
+
+/*/
+/// Sets the directory containing shared state.
+/*/
+void sq_config_home(struct sq_config *cfg, const char *home);
+
+/*/
+/// Set the directory containing backend servers.
+/*/
+void sq_config_lib(struct sq_config *cfg, const char *lib);
+
struct sq_keyid;
struct sq_keyid *sq_keyid_new (uint64_t id);
struct sq_keyid *sq_keyid_from_hex (const char *id);