use rasn::types::ObjectIdentifier;
const DIALOGUE_AS_ID: &[u32] = &[0, 0, 17, 773, 1, 1, 1];
pub fn build_begin_dialogue(ac_oid: &ObjectIdentifier) -> Vec<u8> {
let ac_oid_bytes = encode_oid(ac_oid);
let mut ac_name_tlv = vec![0xA1]; encode_length(&mut ac_name_tlv, ac_oid_bytes.len());
ac_name_tlv.extend_from_slice(&ac_oid_bytes);
let aarq_content = ac_name_tlv;
let mut aarq = vec![0x60];
encode_length(&mut aarq, aarq_content.len());
aarq.extend_from_slice(&aarq_content);
let mut single_asn1 = vec![0xA0];
encode_length(&mut single_asn1, aarq.len());
single_asn1.extend_from_slice(&aarq);
let direct_ref_bytes = encode_oid_raw(DIALOGUE_AS_ID);
let mut direct_ref_tlv = vec![0x06]; encode_length(&mut direct_ref_tlv, direct_ref_bytes.len());
direct_ref_tlv.extend_from_slice(&direct_ref_bytes);
let mut external_content = Vec::new();
external_content.extend_from_slice(&direct_ref_tlv);
external_content.extend_from_slice(&single_asn1);
let mut external = vec![0x28];
encode_length(&mut external, external_content.len());
external.extend_from_slice(&external_content);
external
}
pub fn build_end_dialogue(ac_oid: &ObjectIdentifier) -> Vec<u8> {
let ac_oid_bytes = encode_oid(ac_oid);
let mut ac_name_tlv = vec![0xA1];
encode_length(&mut ac_name_tlv, ac_oid_bytes.len());
ac_name_tlv.extend_from_slice(&ac_oid_bytes);
let result_tlv = vec![0xA2, 0x03, 0x02, 0x01, 0x00];
let diag_tlv = vec![0xA3, 0x05, 0xA1, 0x03, 0x02, 0x01, 0x00];
let mut aare_content = Vec::new();
aare_content.extend_from_slice(&ac_name_tlv);
aare_content.extend_from_slice(&result_tlv);
aare_content.extend_from_slice(&diag_tlv);
let mut aare = vec![0x61];
encode_length(&mut aare, aare_content.len());
aare.extend_from_slice(&aare_content);
let mut single_asn1 = vec![0xA0];
encode_length(&mut single_asn1, aare.len());
single_asn1.extend_from_slice(&aare);
let direct_ref_bytes = encode_oid_raw(DIALOGUE_AS_ID);
let mut direct_ref_tlv = vec![0x06];
encode_length(&mut direct_ref_tlv, direct_ref_bytes.len());
direct_ref_tlv.extend_from_slice(&direct_ref_bytes);
let mut external_content = Vec::new();
external_content.extend_from_slice(&direct_ref_tlv);
external_content.extend_from_slice(&single_asn1);
let mut external = vec![0x28];
encode_length(&mut external, external_content.len());
external.extend_from_slice(&external_content);
external
}
fn encode_oid(oid: &ObjectIdentifier) -> Vec<u8> {
let components: Vec<u32> = oid.iter().copied().collect();
let raw = encode_oid_raw(&components);
let mut tlv = vec![0x06];
encode_length(&mut tlv, raw.len());
tlv.extend_from_slice(&raw);
tlv
}
fn encode_oid_raw(components: &[u32]) -> Vec<u8> {
let mut bytes = Vec::new();
if components.len() >= 2 {
bytes.push((components[0] * 40 + components[1]) as u8);
for &c in &components[2..] {
encode_oid_component(&mut bytes, c);
}
}
bytes
}
fn encode_oid_component(buf: &mut Vec<u8>, value: u32) {
if value < 128 {
buf.push(value as u8);
} else {
let mut temp = Vec::new();
let mut v = value;
temp.push((v & 0x7F) as u8);
v >>= 7;
while v > 0 {
temp.push((v & 0x7F) as u8 | 0x80);
v >>= 7;
}
temp.reverse();
buf.extend_from_slice(&temp);
}
}
fn encode_length(buf: &mut Vec<u8>, len: usize) {
if len < 128 {
buf.push(len as u8);
} else if len < 256 {
buf.push(0x81);
buf.push(len as u8);
} else {
buf.push(0x82);
buf.push((len >> 8) as u8);
buf.push((len & 0xFF) as u8);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::application_context;
#[test]
fn begin_dialogue_has_correct_tags() {
let bytes = build_begin_dialogue(&application_context::short_msg_gateway_context(
application_context::V3,
));
assert_eq!(bytes[0], 0x28, "Expected EXTERNAL tag");
assert!(bytes.contains(&0x06), "Should contain OID tag");
assert!(bytes.contains(&0x60), "Should contain AARQ tag");
}
#[test]
fn end_dialogue_has_correct_tags() {
let bytes = build_end_dialogue(&application_context::short_msg_gateway_context(
application_context::V3,
));
assert_eq!(bytes[0], 0x28, "Expected EXTERNAL tag");
assert!(bytes.contains(&0x61), "Should contain AARE tag");
}
}