///|
/// The server-side sorting request control OID (RFC 2891 1.1).
pub const SORT_REQUEST_OID : String = "1.2.840.113556.1.4.473"
///|
/// The server-side sorting response control OID (RFC 2891 1.2).
pub const SORT_RESPONSE_OID : String = "1.2.840.113556.1.4.474"
///|
/// One sort key of the server-side sort request control (RFC 2891).
pub struct SortKey {
attribute_type : String
ordering_rule : String?
reverse : Bool
} derive(Eq, @debug.Debug)
///|
pub fn SortKey::new(
attribute_type : String,
ordering_rule? : String,
reverse? : Bool,
) -> SortKey {
{
attribute_type,
ordering_rule,
reverse: match reverse {
Some(r) => r
None => false
},
}
}
///|
fn encode_sort_key(key : SortKey) -> Bytes {
let mut content = encode_ldap_string(key.attribute_type)
match key.ordering_rule {
Some(rule) =>
content = content + encode_tlv(context_tag(0, false), @utf8.encode(rule))
None => ()
}
if key.reverse {
content = content + encode_boolean(true)
}
encode_sequence([content])
}
///|
/// Build the server-side sort request control for a key list.
pub fn sort_request_control(keys : Array[SortKey]) -> Control {
let mut list = Bytes::new(0)
for key in keys {
list = list + encode_sort_key(key)
}
Control::new(SORT_REQUEST_OID, false, encode_sequence([list]))
}
///|
pub struct SortResponse {
result : ResultCode
attribute_type : String?
} derive(Eq, @debug.Debug)
///|
/// Encode a sort response control value (used by tests and mock servers).
pub fn sort_response_value(
sort_result : Int,
attribute_type : String?,
) -> Bytes {
let mut content = encode_enumerated(sort_result)
match attribute_type {
Some(attr) =>
content = content + encode_tlv(context_tag(0, false), @utf8.encode(attr))
None => ()
}
encode_sequence([content])
}
///|
/// Extract the server-side sort response control, returning `None` when
/// absent or malformed.
pub fn parse_sort_response(controls : Array[Control]?) -> SortResponse? {
match controls {
Some(list) =>
for ctrl in list {
if ctrl.control_type == SORT_RESPONSE_OID {
let decoded = match decode_ber(ctrl.control_value, None) {
Ok(v) => v
Err(_) => return None
}
let kids = decoded.children_or_empty()
if kids.length() < 1 {
return None
}
let code = match parse_integer(kids[0].content, 8) {
Ok(v) => v
Err(_) => return None
}
let mut attr : String? = None
if kids.length() > 1 &&
kids[1].tag.class == ContextSpecific &&
kids[1].tag.number == 0 {
attr = Some(@utf8.decode_lossy(kids[1].content[:]))
}
return Some({
result: ResultCode::from_int(code),
attribute_type: attr,
})
}
}
None => ()
}
None
}