#![forbid(unsafe_code)]
use crate::error::ErrorCode;
use std::ffi::{CStr, CString};
use std::result::Result;
#[rustversion::attr(since(1.48), doc(alias = "pam_conv"))]
pub trait ConversationHandler {
fn init(&mut self, _default_user: Option<&str>) {}
fn prompt_echo_on(&mut self, prompt: &CStr) -> Result<CString, ErrorCode>;
fn prompt_echo_off(&mut self, prompt: &CStr) -> Result<CString, ErrorCode>;
fn text_info(&mut self, msg: &CStr);
fn error_msg(&mut self, msg: &CStr);
fn radio_prompt(&mut self, prompt: &CStr) -> Result<bool, ErrorCode> {
let prompt = [prompt.to_bytes(), b" [y/N]\0"].concat();
self.prompt_echo_on(CStr::from_bytes_with_nul(&prompt).unwrap())
.map(|s| matches!(s.as_bytes_with_nul()[0], b'Y' | b'y' | b'j' | b'J'))
}
fn binary_prompt(&mut self, _type: u8, _data: &[u8]) -> Result<(u8, Vec<u8>), ErrorCode> {
Err(ErrorCode::CONV_ERR)
}
}
macro_rules! impl_for_wrapper {
($type:ty) => {
impl_for_wrapper!($type, <>);
};
($type:ty, $($params:tt)*) => {
impl $($params)* ConversationHandler for $type {
#[inline]
fn init(&mut self, default_user: Option<&str>) {
(**self).init(default_user)
}
#[inline]
fn prompt_echo_on(&mut self, prompt: &CStr) -> Result<CString, ErrorCode> {
(**self).prompt_echo_on(prompt)
}
#[inline]
fn prompt_echo_off(&mut self, prompt: &CStr) -> Result<CString, ErrorCode> {
(**self).prompt_echo_off(prompt)
}
#[inline]
fn text_info(&mut self, msg: &CStr) {
(**self).text_info(msg)
}
#[inline]
fn error_msg(&mut self, msg: &CStr) {
(**self).error_msg(msg)
}
#[inline]
fn radio_prompt(&mut self, prompt: &CStr) -> Result<bool, ErrorCode> {
(**self).radio_prompt(prompt)
}
#[inline]
fn binary_prompt(
&mut self,
type_: u8,
data: &[u8],
) -> Result<(u8, Vec<u8>), ErrorCode> {
(**self).binary_prompt(type_, data)
}
}
};
}
impl_for_wrapper!(&'a mut T, <'a, T: ConversationHandler + ?Sized>);
impl_for_wrapper!(Box<T>, <T: ConversationHandler + ?Sized>);