use nom::{number::complete::be_u8, IResult};
use crate::{common::parse_c_octet_string_nom, CommandHeader, CommandId, SmppError, SmppReply};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct cancel_sm {
pub header: CommandHeader,
pub service_type: String,
pub message_id: String,
pub source_addr_ton: u8,
pub source_addr_npi: u8,
pub source_addr: String,
pub dest_addr_ton: u8,
pub dest_addr_npi: u8,
pub destination_addr: String,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct cancel_sm_resp {
header: CommandHeader,
}
impl SmppReply for cancel_sm_resp {}
fn parse_cancel_sm(header: CommandHeader, pdu: &[u8]) -> IResult<&[u8], cancel_sm> {
let (pdu, service_type) = parse_c_octet_string_nom(pdu)?;
let (pdu, message_id) = parse_c_octet_string_nom(pdu)?;
let (pdu, source_addr_ton) = be_u8(pdu)?;
let (pdu, source_addr_npi) = be_u8(pdu)?;
let (pdu, source_addr) = parse_c_octet_string_nom(pdu)?;
let (pdu, dest_addr_ton) = be_u8(pdu)?;
let (pdu, dest_addr_npi) = be_u8(pdu)?;
let (pdu, destination_addr) = parse_c_octet_string_nom(pdu)?;
Ok((
pdu,
cancel_sm {
header,
service_type,
message_id,
source_addr_ton,
source_addr_npi,
source_addr,
dest_addr_ton,
dest_addr_npi,
destination_addr,
},
))
}
fn parse_cancel_sm_resp(header: CommandHeader, pdu: &[u8]) -> IResult<&[u8], cancel_sm_resp> {
Ok((pdu, cancel_sm_resp { header }))
}
impl cancel_sm {
pub(crate) fn new(
sequence_number: u32,
service_type: String,
message_id: String,
source_addr_ton: u8,
source_addr_npi: u8,
source_addr: String,
dest_addr_ton: u8,
dest_addr_npi: u8,
destination_addr: String,
) -> cancel_sm {
assert!(service_type.len() < 6, "service_type can be a maximum of 6 octets including NULL terminator for C-Octet-String");
assert!(source_addr.len() < 21, "source_addr can be a maximum of 21 octets including NULL terminator for C-Octet-String");
assert!(destination_addr.len() < 21, "destination_addr can be a maximum of 21 octets including NULL terminator for C-Octet-String");
cancel_sm {
header: CommandHeader {
command_length: (16
+ service_type.len()
+ 1
+ 2
+ source_addr.len()
+ 1
+ 2
+ destination_addr.len()
+ 1) as u32,
command_id: CommandId::cancel_sm as u32,
command_status: SmppError::ESME_ROK as u32,
sequence_number,
},
service_type,
message_id,
source_addr_ton,
source_addr_npi,
source_addr,
dest_addr_ton,
dest_addr_npi,
destination_addr,
}
}
pub fn decode(header: CommandHeader, pdu: &[u8]) -> Result<cancel_sm, SmppError> {
match parse_cancel_sm(header, pdu) {
Ok((_, cancel_sm)) => Ok(cancel_sm),
Err(_) => Err(SmppError::ESME_RINVPARLEN),
}
}
pub fn encode(self) -> Vec<u8> {
let mut buffer: Vec<u8> = Vec::with_capacity(self.header.command_status as usize);
buffer.append(&mut self.header.encode());
buffer.append(&mut self.service_type.into_bytes());
buffer.push(0x00); buffer.append(&mut self.message_id.into_bytes());
buffer.push(0x00); buffer.push(self.source_addr_ton);
buffer.push(self.source_addr_npi);
buffer.append(&mut self.source_addr.into_bytes());
buffer.push(0x00); buffer.push(self.dest_addr_ton);
buffer.push(self.dest_addr_npi);
buffer.append(&mut self.destination_addr.into_bytes());
buffer.push(0x00); buffer
}
pub fn accept(self) -> cancel_sm_resp {
cancel_sm_resp {
header: CommandHeader {
command_length: 16,
command_id: CommandId::cancel_sm_resp as u32,
command_status: SmppError::ESME_ROK as u32,
sequence_number: self.header.sequence_number,
},
}
}
pub fn reject(self, error: SmppError) -> cancel_sm_resp {
cancel_sm_resp {
header: CommandHeader {
command_length: 16,
command_id: CommandId::cancel_sm_resp as u32,
command_status: error as u32,
sequence_number: self.header.sequence_number,
},
}
}
pub fn generic_reject(sequence_number: u32, error: SmppError) -> cancel_sm_resp {
cancel_sm_resp {
header: CommandHeader {
command_length: 16,
command_id: CommandId::cancel_sm_resp as u32,
command_status: error as u32,
sequence_number,
},
}
}
}
impl cancel_sm_resp {
pub fn is_success(&self) -> bool {
self.header.command_status == SmppError::ESME_ROK as u32
}
pub fn command_status(&self) -> u32 {
self.header.command_status
}
pub fn get_error(&self) -> SmppError {
SmppError::from_command_status(self.header.command_status)
}
pub fn decode(header: CommandHeader, pdu: &[u8]) -> Result<cancel_sm_resp, SmppError> {
match parse_cancel_sm_resp(header, pdu) {
Ok((_, cancel_sm_resp)) => Ok(cancel_sm_resp),
Err(_) => Err(SmppError::ESME_RINVPARLEN),
}
}
pub fn encode(self) -> Vec<u8> {
let mut buffer: Vec<u8> = Vec::with_capacity(self.header.command_status as usize);
buffer.append(&mut self.header.encode());
buffer
}
}
#[cfg(test)]
mod all_cancel_sm_tests {
#[cfg(test)]
mod cancel_sm_tests {
use crate::{cancel_sm, CommandHeader, CommandId, SmppError};
#[test]
fn decode_cancel_sm() {
let pdu = vec![
0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x45, 0x67, b't', b'e', b's', b't', 0x00, b'M', b'e', b's', b's', b'a', b'g', b'e', b'I', b'D', 0x00, 0x01, 0x01, b's', b'o', b'u', b'r', b'c', b'e', 0x00, 0x01, 0x01, b'd', b'e', b's', b't', b'_', b'a', b'd', b'd', b'r',
0x00, ];
let decoded_command_header =
CommandHeader::decode(&pdu).expect("Can not decode command header");
let decoded = cancel_sm::decode(decoded_command_header, &pdu[16..])
.expect("Unable to decode unbind");
assert_eq!(decoded.header.command_length, 52);
assert_eq!(decoded.header.command_id, CommandId::cancel_sm as u32);
assert_eq!(decoded.header.command_status, SmppError::ESME_ROK as u32);
assert_eq!(decoded.header.sequence_number, 0x12344567);
assert_eq!(decoded.service_type, "test");
assert_eq!(decoded.message_id, "MessageID");
assert_eq!(decoded.source_addr_ton, 0x01);
assert_eq!(decoded.source_addr_npi, 0x01);
assert_eq!(decoded.source_addr, "source");
assert_eq!(decoded.dest_addr_ton, 0x01);
assert_eq!(decoded.dest_addr_npi, 0x01);
assert_eq!(decoded.destination_addr, "dest_addr");
}
#[test]
fn encode_cancel_sm() {
let cancel_sm = cancel_sm::new(
0x12345678,
"test".to_string(),
"MessageID".to_string(),
0x01,
0x01,
"source".to_string(),
0x01,
0x01,
"dest_addr".to_string(),
);
let encoded = cancel_sm.encode();
let expected_pdu = vec![
0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, b't', b'e', b's', b't', 0x00, b'M', b'e', b's', b's', b'a', b'g', b'e', b'I', b'D', 0x00, 0x01, 0x01, b's', b'o', b'u', b'r', b'c', b'e', 0x00, 0x01, 0x01, b'd', b'e', b's', b't', b'_', b'a', b'd', b'd', b'r',
0x00, ];
assert_eq!(encoded, expected_pdu);
}
}
#[cfg(test)]
mod cancel_sm_resp_tests {
#[cfg(test)]
mod cancel_sm_resp_tests {
use crate::{cancel_sm, SmppError};
#[test]
fn encode_cancel_sm_resp() {
let cancel_sm = cancel_sm::new(
0x12345678,
"test".to_string(),
"MessageID".to_string(),
0x01,
0x01,
"source".to_string(),
0x01,
0x01,
"dest_addr".to_string(),
);
let cancel_sm_resp = cancel_sm.accept();
let encoded = cancel_sm_resp.encode();
let expected_pdu = vec![
0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, ];
assert_eq!(encoded, expected_pdu);
}
#[test]
fn encode_cancel_sm_resp_reject() {
let cancel_sm = cancel_sm::new(
0x12345678,
"test".to_string(),
"MessageID".to_string(),
0x01,
0x01,
"source".to_string(),
0x01,
0x01,
"dest_addr".to_string(),
);
let cancel_sm_resp_rejected = cancel_sm.reject(SmppError::ESME_RINVPARLEN);
let encoded_rejected = cancel_sm_resp_rejected.encode();
let expected_pdu_rejected = vec![
0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xC2, 0x12, 0x34, 0x56, 0x78, ];
assert_eq!(encoded_rejected, expected_pdu_rejected);
}
}
}
}