use std::collections::HashMap;
use lber::structure::{StructureTag, PL};
use lber::structures::{ASNTag, Boolean, OctetString, Sequence, Tag};
use lber::universal::Types;
use lazy_static::lazy_static;
#[non_exhaustive]
#[derive(Clone, Copy, Debug)]
pub enum ControlType {
PagedResults,
PostReadResp,
PreReadResp,
SyncDone,
SyncState,
ManageDsaIt,
MatchedValues,
}
mod assertion;
pub use self::assertion::Assertion;
mod content_sync;
pub use self::content_sync::parse_syncinfo;
pub use self::content_sync::{EntryState, RefreshMode, SyncDone, SyncInfo, SyncRequest, SyncState};
mod paged_results;
pub use self::paged_results::PagedResults;
mod proxy_auth;
pub use self::proxy_auth::ProxyAuth;
mod read_entry;
pub use self::read_entry::{PostRead, PostReadResp, PreRead, PreReadResp, ReadEntryResp};
mod relax_rules;
pub use self::relax_rules::RelaxRules;
mod manage_dsa_it;
pub use self::manage_dsa_it::ManageDsaIt;
mod matched_values;
pub use self::matched_values::MatchedValues;
#[rustfmt::skip]
lazy_static! {
static ref CONTROLS: HashMap<&'static str, ControlType> = {
let mut map = HashMap::new();
map.insert(self::paged_results::PAGED_RESULTS_OID, ControlType::PagedResults);
map.insert(self::read_entry::POST_READ_OID, ControlType::PostReadResp);
map.insert(self::read_entry::PRE_READ_OID, ControlType::PreReadResp);
map.insert(self::content_sync::SYNC_DONE_OID, ControlType::SyncDone);
map.insert(self::content_sync::SYNC_STATE_OID, ControlType::SyncState);
map.insert(self::manage_dsa_it::MANAGE_DSA_IT_OID, ControlType::ManageDsaIt);
map.insert(self::matched_values::MATCHED_VALUES_OID, ControlType::MatchedValues);
map
};
}
pub trait IntoRawControlVec {
fn into(self) -> Vec<RawControl>;
}
impl IntoRawControlVec for Vec<RawControl> {
fn into(self) -> Vec<RawControl> {
self
}
}
impl<R> IntoRawControlVec for R
where
RawControl: From<R>,
{
fn into(self) -> Vec<RawControl> {
vec![std::convert::Into::into(self)]
}
}
pub trait MakeCritical {
fn critical(self) -> CriticalControl<Self>
where
Self: Sized,
{
CriticalControl { control: self }
}
}
pub struct CriticalControl<T> {
control: T,
}
impl<T> From<CriticalControl<T>> for RawControl
where
T: Into<RawControl>,
{
fn from(cc: CriticalControl<T>) -> RawControl {
let mut rc = cc.control.into();
rc.crit = true;
rc
}
}
pub trait ControlParser {
fn parse(val: &[u8]) -> Self;
}
#[derive(Clone, Debug)]
pub struct Control(pub Option<ControlType>, pub RawControl);
#[derive(Clone, Debug)]
pub struct RawControl {
pub ctype: String,
pub crit: bool,
pub val: Option<Vec<u8>>,
}
impl RawControl {
pub fn parse<T: ControlParser>(&self) -> T {
T::parse(self.val.as_ref().expect("value"))
}
}
pub fn build_tag(rc: RawControl) -> StructureTag {
let mut seq = vec![Tag::OctetString(OctetString {
inner: Vec::from(rc.ctype.as_bytes()),
..Default::default()
})];
if rc.crit {
seq.push(Tag::Boolean(Boolean {
inner: true,
..Default::default()
}));
}
if let Some(val) = rc.val {
seq.push(Tag::OctetString(OctetString {
inner: val,
..Default::default()
}));
}
Tag::Sequence(Sequence {
inner: seq,
..Default::default()
})
.into_structure()
}
pub fn parse_controls(t: StructureTag) -> Vec<Control> {
let tags = t.expect_constructed().expect("result sequence").into_iter();
let mut ctrls = Vec::new();
for ctrl in tags {
let mut components = ctrl.expect_constructed().expect("components").into_iter();
let ctype = String::from_utf8(
components
.next()
.expect("element")
.expect_primitive()
.expect("octet string"),
)
.expect("control type");
let next = components.next();
let (crit, maybe_val) = match next {
None => (false, None),
Some(c) => match c {
StructureTag {
id, ref payload, ..
} if id == Types::Boolean as u64 => match *payload {
PL::P(ref v) => (v[0] != 0, components.next()),
PL::C(_) => panic!("decoding error"),
},
StructureTag { id, .. } if id == Types::OctetString as u64 => {
(false, Some(c.clone()))
}
_ => panic!("decoding error"),
},
};
let val = maybe_val.map(|v| v.expect_primitive().expect("octet string"));
let known_type = CONTROLS.get(&*ctype).copied();
ctrls.push(Control(known_type, RawControl { ctype, crit, val }));
}
ctrls
}