use crate::context::Context;
use crate::error::{self, check, Result};
use crate::ffi;
use crate::ffi_safe::{call_for_string, call_for_usize};
use crate::key::{KeyIdentifier, LoadSaveFlags, UnloadFlags};
use crate::ops::Input;
use std::ffi::CString;
use std::os::raw::c_char;
use std::path::PathBuf;
use std::ptr;
impl Context {
pub fn save_keys(
&self,
format: crate::context::KeyringFormat,
flags: LoadSaveFlags,
output: &mut crate::Output,
) -> Result<()> {
let fmt_c = CString::new(format.as_str()).unwrap();
unsafe { check(ffi::rnp_save_keys(self.ffi, fmt_c.as_ptr(), output.as_ptr(), flags.bits())) }
}
pub fn save_keys_to_memory(
&self,
format: crate::context::KeyringFormat,
flags: LoadSaveFlags,
) -> Result<Vec<u8>> {
let mut output = crate::Output::to_memory()?;
self.save_keys(format, flags, &mut output)?;
output.into_bytes()
}
pub fn unload_keys(&self, flags: UnloadFlags) -> Result<()> {
unsafe { check(ffi::rnp_unload_keys(self.ffi, flags.bits())) }
}
pub fn import_keys(
&self,
bytes: &[u8],
flags: crate::key::LoadSaveFlags,
) -> Result<String> {
let input = Input::from_memory(bytes)?;
call_for_string(|raw| unsafe {
ffi::rnp_import_keys(self.ffi, input.as_ptr(), flags.bits(), raw)
})
}
pub fn import_signatures(&self, bytes: &[u8], flags: u32) -> Result<String> {
let input = Input::from_memory(bytes)?;
call_for_string(|raw| unsafe {
ffi::rnp_import_signatures(self.ffi, input.as_ptr(), flags, raw)
})
}
pub fn public_key_count(&self) -> Result<usize> {
call_for_usize(|out| unsafe { ffi::rnp_get_public_key_count(self.ffi, out) })
}
pub fn secret_key_count(&self) -> Result<usize> {
call_for_usize(|out| unsafe { ffi::rnp_get_secret_key_count(self.ffi, out) })
}
pub fn default_homedir() -> Result<PathBuf> {
let s = call_for_string(|out| unsafe { ffi::rnp_get_default_homedir(out) })?;
Ok(PathBuf::from(s))
}
pub fn detect_homedir_info(path: &str) -> Result<(String, String, String, String)> {
let c = CString::new(path).map_err(|_| error::Error::PathNul)?;
let mut pub_fmt: *mut c_char = ptr::null_mut();
let mut pub_path: *mut c_char = ptr::null_mut();
let mut sec_fmt: *mut c_char = ptr::null_mut();
let mut sec_path: *mut c_char = ptr::null_mut();
unsafe {
check(ffi::rnp_detect_homedir_info(
c.as_ptr(),
&mut pub_fmt,
&mut pub_path,
&mut sec_fmt,
&mut sec_path,
))?;
let pf = crate::ops::cstr_to_optional_string(pub_fmt).unwrap_or_default();
let pp = crate::ops::cstr_to_optional_string(pub_path).unwrap_or_default();
let sf = crate::ops::cstr_to_optional_string(sec_fmt).unwrap_or_default();
let sp = crate::ops::cstr_to_optional_string(sec_path).unwrap_or_default();
Ok((pf, pp, sf, sp))
}
}
pub fn detect_key_format(bytes: &[u8]) -> Result<String> {
call_for_string(|out| unsafe {
ffi::rnp_detect_key_format(bytes.as_ptr(), bytes.len(), out)
})
}
pub fn identifiers(&self, kind: IdentifierKind) -> Result<IdentifierIterator<'_>> {
IdentifierIterator::new(self, kind)
}
}
#[derive(Clone, Copy, Debug)]
pub enum IdentifierKind {
Userid,
Keyid,
Grip,
Fingerprint,
}
impl IdentifierKind {
fn as_str(self) -> &'static str {
match self {
IdentifierKind::Userid => "userid",
IdentifierKind::Keyid => "keyid",
IdentifierKind::Grip => "grip",
IdentifierKind::Fingerprint => "fingerprint",
}
}
}
pub struct IdentifierIterator<'ctx> {
handle: ffi::rnp_identifier_iterator_t,
_ctx: std::marker::PhantomData<&'ctx Context>,
}
impl<'ctx> IdentifierIterator<'ctx> {
fn new(ctx: &'ctx Context, kind: IdentifierKind) -> Result<Self> {
let kind_c = CString::new(kind.as_str()).unwrap();
let mut handle: ffi::rnp_identifier_iterator_t = ptr::null_mut();
unsafe {
check(ffi::rnp_identifier_iterator_create(
ctx.ffi,
&mut handle,
kind_c.as_ptr(),
))?;
}
if handle.is_null() {
return Err(error::Error::NullPointer);
}
Ok(IdentifierIterator {
handle,
_ctx: std::marker::PhantomData,
})
}
}
impl<'ctx> Iterator for IdentifierIterator<'ctx> {
type Item = String;
fn next(&mut self) -> Option<String> {
let mut raw: *const c_char = ptr::null();
let code = unsafe { ffi::rnp_identifier_iterator_next(self.handle, &mut raw) };
if code != error::SUCCESS || raw.is_null() {
return None;
}
unsafe {
let cs = std::ffi::CStr::from_ptr(raw);
Some(cs.to_string_lossy().into_owned())
}
}
}
impl<'ctx> Drop for IdentifierIterator<'ctx> {
fn drop(&mut self) {
if !self.handle.is_null() {
unsafe {
let _ = ffi::rnp_identifier_iterator_destroy(self.handle);
}
self.handle = ptr::null_mut();
}
}
}
#[allow(unused_imports)]
use KeyIdentifier as _KeyIdentifierAlias;