use crate::context::Context;
use crate::error::{self, check, Result};
use crate::ffi;
use crate::ffi_safe::{call_for_usize, cstr_to_optional_string, cstr_to_string};
use std::marker::PhantomData;
use std::os::raw::c_char;
use std::ptr;
use super::{FileInfo, Recipient, Symenc, VerifySignature};
pub struct VerifyResult<'ctx> {
pub(crate) ctx: &'ctx Context,
pub(crate) op: ffi::rnp_op_verify_t,
pub(crate) _phantom: PhantomData<&'ctx ()>,
}
impl<'ctx> VerifyResult<'ctx> {
pub fn context(&self) -> &Context {
self.ctx
}
pub fn signature_count(&self) -> Result<usize> {
call_for_usize(|out| unsafe { ffi::rnp_op_verify_get_signature_count(self.op, out) })
}
pub fn signature_at(&self, idx: usize) -> Result<Option<VerifySignature>> {
let mut handle: ffi::rnp_op_verify_signature_t = ptr::null_mut();
unsafe {
check(ffi::rnp_op_verify_get_signature_at(self.op, idx, &mut handle))?;
}
if handle.is_null() {
Ok(None)
} else {
Ok(Some(VerifySignature::new(handle)))
}
}
pub fn signatures(&self) -> Result<Vec<VerifySignature>> {
let n = self.signature_count()?;
(0..n)
.map(|i| self.signature_at(i)?.ok_or(error::Error::NullPointer))
.collect()
}
pub fn iter_signatures(&self) -> impl Iterator<Item = VerifySignature> + '_ {
let n = self.signature_count().unwrap_or(0);
(0..n).filter_map(move |i| self.signature_at(i).ok().flatten())
}
pub fn any_valid(&self) -> Result<bool> {
let sigs = self.signatures()?;
Ok(sigs.iter().any(|s| s.status_is_valid()))
}
pub fn recipient_count(&self) -> Result<usize> {
call_for_usize(|out| unsafe { ffi::rnp_op_verify_get_recipient_count(self.op, out) })
}
pub fn recipient_at(&self, idx: usize) -> Result<Option<Recipient>> {
let mut handle: ffi::rnp_recipient_handle_t = ptr::null_mut();
unsafe {
check(ffi::rnp_op_verify_get_recipient_at(self.op, idx, &mut handle))?;
}
if handle.is_null() {
Ok(None)
} else {
Ok(Some(Recipient::new(handle)))
}
}
pub fn recipients(&self) -> Result<Vec<Recipient>> {
let n = self.recipient_count()?;
(0..n)
.map(|i| self.recipient_at(i)?.ok_or(error::Error::NullPointer))
.collect()
}
pub fn used_recipient(&self) -> Result<Option<Recipient>> {
let mut handle: ffi::rnp_recipient_handle_t = ptr::null_mut();
unsafe {
check(ffi::rnp_op_verify_get_used_recipient(self.op, &mut handle))?;
}
if handle.is_null() {
Ok(None)
} else {
Ok(Some(Recipient::new(handle)))
}
}
pub fn symenc_count(&self) -> Result<usize> {
call_for_usize(|out| unsafe { ffi::rnp_op_verify_get_symenc_count(self.op, out) })
}
pub fn symenc_at(&self, idx: usize) -> Result<Option<Symenc>> {
let mut handle: ffi::rnp_symenc_handle_t = ptr::null_mut();
unsafe {
check(ffi::rnp_op_verify_get_symenc_at(self.op, idx, &mut handle))?;
}
if handle.is_null() {
Ok(None)
} else {
Ok(Some(Symenc::new(handle)))
}
}
pub fn symencs(&self) -> Result<Vec<Symenc>> {
let n = self.symenc_count()?;
(0..n)
.map(|i| self.symenc_at(i)?.ok_or(error::Error::NullPointer))
.collect()
}
pub fn used_symenc(&self) -> Result<Option<Symenc>> {
let mut handle: ffi::rnp_symenc_handle_t = ptr::null_mut();
unsafe {
check(ffi::rnp_op_verify_get_used_symenc(self.op, &mut handle))?;
}
if handle.is_null() {
Ok(None)
} else {
Ok(Some(Symenc::new(handle)))
}
}
pub fn file_info(&self) -> Result<Option<FileInfo>> {
let mut name_raw: *mut c_char = ptr::null_mut();
let mut mtime: u32 = 0;
unsafe {
let code = ffi::rnp_op_verify_get_file_info(self.op, &mut name_raw, &mut mtime);
if code == error::NOT_FOUND {
return Ok(None);
}
check(code)?;
let name = cstr_to_optional_string(name_raw).unwrap_or_default();
Ok(Some(FileInfo { name, mtime }))
}
}
pub fn format(&self) -> Result<char> {
let mut c: std::os::raw::c_char = 0;
unsafe {
check(ffi::rnp_op_verify_get_format(self.op, &mut c))?;
}
Ok(c as u8 as char)
}
pub fn protection_info(&self) -> Result<(String, String, bool)> {
let mut mode_raw: *mut c_char = ptr::null_mut();
let mut cipher_raw: *mut c_char = ptr::null_mut();
let mut valid: bool = false;
unsafe {
check(ffi::rnp_op_verify_get_protection_info(
self.op,
&mut mode_raw,
&mut cipher_raw,
&mut valid,
))?;
let mode = cstr_to_string(mode_raw)?;
let cipher = cstr_to_string(cipher_raw)?;
Ok((mode, cipher, valid))
}
}
}
impl<'ctx> Drop for VerifyResult<'ctx> {
fn drop(&mut self) {
if !self.op.is_null() {
unsafe {
let _ = ffi::rnp_op_verify_destroy(self.op);
}
self.op = ptr::null_mut();
}
}
}