use log::error;
use crate::{common::parse_c_octet_string, CommandHeader, CommandId, SmppError};
#[derive(Debug, Clone)]
pub struct outbind {
header: CommandHeader,
system_id: String,
password: String,
}
impl outbind {
pub fn new(seq_no: u32, system_id: String, password: String) -> outbind {
outbind {
header: CommandHeader {
command_length: (16 + system_id.len() + password.len() + 2) as u32,
command_id: CommandId::outbind as u32,
command_status: SmppError::ESME_ROK as u32,
sequence_number: seq_no,
},
system_id,
password,
}
}
pub fn decode(header: CommandHeader, pdu: &[u8]) -> Result<outbind, SmppError> {
if header.command_id == CommandId::outbind as u32 {
if pdu.len() >= 18 {
let system_id = parse_c_octet_string(pdu[16..].to_vec(), 16)?;
let password = parse_c_octet_string(pdu[16 + system_id.len() + 1..].to_vec(), 9)?;
Ok(outbind {
header,
system_id,
password,
})
} else {
Err(SmppError::ESME_RINVPARLEN) }
} else {
error!(
"Passed a non outbind PDU to outbind::decode(), command_id: 0x{:08X}",
header.command_id
);
Err(SmppError::ESME_RINVCMDID)
}
}
pub fn encode(self) -> Vec<u8> {
if self.system_id.len() > 16 {
panic!("system_id can only be 16 digits long")
} else if self.password.len() > 9 {
panic!("password can only be 9 digits long")
} else {
let mut buffer: Vec<u8> =
Vec::with_capacity(16 + self.system_id.len() + self.password.len() + 2); buffer.append(&mut self.header.encode());
buffer.append(&mut self.system_id.as_bytes().to_vec());
buffer.push(0x00);
buffer.append(&mut self.password.as_bytes().to_vec());
buffer.push(0x00);
buffer
}
}
}
#[cfg(test)]
mod outbind_tests {
use crate::{outbind, CommandHeader, CommandId, SmppError};
#[test]
fn new_outbind() {
let outbind = outbind::new(0x1234, "abc".to_owned(), "123".to_owned());
assert_eq!(outbind.header.command_length, 24);
assert_eq!(outbind.header.command_id, CommandId::outbind as u32);
assert_eq!(outbind.header.command_status, SmppError::ESME_ROK as u32);
assert_eq!(outbind.header.sequence_number, 0x1234);
assert_eq!(outbind.system_id, "abc");
assert_eq!(outbind.password, "123");
}
#[test]
fn encode_outbind() {
let outbind = outbind::new(0x1234, "abc".to_owned(), "123".to_owned());
let pdu = outbind.encode();
assert_eq!(
pdu,
vec![
0x00, 0x0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x12, 0x34, 0x61, 0x62, 0x63, 0x00, 0x31, 0x32, 0x33, 0x00
]
);
}
#[test]
fn decode_outbind() {
let pdu = vec![
0x00, 0x0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x12, 0x34, 0x61, 0x62, 0x63, 0x00, 0x31, 0x32, 0x33, 0x00,
];
let decoded_command_header =
CommandHeader::decode(&pdu).expect("Can not decode command header");
let decoded =
outbind::decode(decoded_command_header, &pdu).expect("Unable to decode outbind");
assert_eq!(decoded.header.command_length, 24);
assert_eq!(decoded.header.command_id, CommandId::outbind as u32);
assert_eq!(decoded.header.command_status, SmppError::ESME_ROK as u32);
assert_eq!(decoded.header.sequence_number, 0x1234);
assert_eq!(decoded.system_id, "abc");
assert_eq!(decoded.password, "123");
}
#[test]
fn decode_outbind_empty_system_id_and_password() {
let pdu = vec![
0x00, 0x0, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x12, 0x34, 0x00, 0x00,
];
let decoded_command_header =
CommandHeader::decode(&pdu).expect("Can not decode command header");
let decoded =
outbind::decode(decoded_command_header, &pdu).expect("Unable to decode outbind");
assert_eq!(decoded.header.command_length, 18);
assert_eq!(decoded.header.command_id, CommandId::outbind as u32);
assert_eq!(decoded.header.command_status, SmppError::ESME_ROK as u32);
assert_eq!(decoded.header.sequence_number, 0x1234);
assert_eq!(decoded.system_id, "");
assert_eq!(decoded.password, "");
}
#[test]
fn decode_outbind_without_body() {
let pdu = vec![
0x00, 0x0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x12, 0x34,
];
let decoded_command_header =
CommandHeader::decode(&pdu).expect("Can not decode command header");
let decoded = outbind::decode(decoded_command_header, &pdu).unwrap_err();
assert_eq!(decoded, SmppError::ESME_RINVPARLEN)
}
#[test]
fn decode_outbind_with_invalid_command_id() {
let pdu = vec![
0x00, 0x0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x12, 0x34, 0x61, 0x62, 0x63, 0x00, 0x31, 0x32, 0x33, 0x00,
];
let decoded_command_header =
CommandHeader::decode(&pdu).expect("Can not decode command header");
let result = outbind::decode(decoded_command_header, &pdu);
assert!(result.is_err());
}
}