use crate::common::{
read_c_string, write_c_string, Npi, PduError, Ton, CMD_BROADCAST_SM, HEADER_LEN,
};
use crate::tlv::{tags, Tlv};
use std::io::{Cursor, Read, Write};
#[derive(Debug, Clone, PartialEq)]
pub struct BroadcastSm {
pub sequence_number: u32,
pub service_type: String,
pub source_addr_ton: Ton,
pub source_addr_npi: Npi,
pub source_addr: String,
pub message_id: String, pub priority_flag: u8,
pub schedule_delivery_time: String,
pub validity_period: String,
pub replace_if_present_flag: u8,
pub data_coding: u8,
pub sm_default_msg_id: u8,
pub optional_params: Vec<Tlv>, }
impl BroadcastSm {
pub fn new(
sequence_number: u32,
source_addr: String,
payload: Vec<u8>,
area_tlv: Tlv, ) -> Self {
let mut pdu = Self {
sequence_number,
service_type: String::new(),
source_addr_ton: Ton::Unknown,
source_addr_npi: Npi::Unknown,
source_addr,
message_id: String::new(),
priority_flag: 0,
schedule_delivery_time: String::new(),
validity_period: String::new(),
replace_if_present_flag: 0,
data_coding: 0,
sm_default_msg_id: 0,
optional_params: Vec::new(),
};
pdu.add_tlv(Tlv::new(tags::MESSAGE_PAYLOAD, payload));
pdu.add_tlv(area_tlv);
pdu
}
pub fn add_tlv(&mut self, tlv: Tlv) {
self.optional_params.push(tlv);
}
pub fn encode(&self, writer: &mut impl Write) -> Result<(), PduError> {
let tlvs_len: usize = self
.optional_params
.iter()
.map(|t| 4 + t.length as usize)
.sum();
let body_len = self.service_type.len() + 1 +
1 + 1 + self.source_addr.len() + 1 +
self.message_id.len() + 1 +
1 + self.schedule_delivery_time.len() + 1 +
self.validity_period.len() + 1 +
1 + 1 + 1 + tlvs_len;
let command_len = (HEADER_LEN + body_len) as u32;
writer.write_all(&command_len.to_be_bytes())?;
writer.write_all(&CMD_BROADCAST_SM.to_be_bytes())?;
writer.write_all(&0u32.to_be_bytes())?;
writer.write_all(&self.sequence_number.to_be_bytes())?;
write_c_string(writer, &self.service_type)?;
writer.write_all(&[self.source_addr_ton as u8, self.source_addr_npi as u8])?;
write_c_string(writer, &self.source_addr)?;
write_c_string(writer, &self.message_id)?;
writer.write_all(&[self.priority_flag])?;
write_c_string(writer, &self.schedule_delivery_time)?;
write_c_string(writer, &self.validity_period)?;
writer.write_all(&[
self.replace_if_present_flag,
self.data_coding,
self.sm_default_msg_id,
])?;
for tlv in &self.optional_params {
tlv.encode(writer)?;
}
Ok(())
}
pub fn decode(buffer: &[u8]) -> Result<Self, PduError> {
if buffer.len() < HEADER_LEN {
return Err(PduError::BufferTooShort);
}
let mut cursor = Cursor::new(buffer);
cursor.set_position(12);
let mut bytes = [0u8; 4];
cursor.read_exact(&mut bytes)?;
let sequence_number = u32::from_be_bytes(bytes);
let service_type = read_c_string(&mut cursor)?;
let mut u8_buf = [0u8; 1];
cursor.read_exact(&mut u8_buf)?;
let source_addr_ton = Ton::from(u8_buf[0]);
cursor.read_exact(&mut u8_buf)?;
let source_addr_npi = Npi::from(u8_buf[0]);
let source_addr = read_c_string(&mut cursor)?;
let message_id = read_c_string(&mut cursor)?;
cursor.read_exact(&mut u8_buf)?;
let priority_flag = u8_buf[0];
let schedule_delivery_time = read_c_string(&mut cursor)?;
let validity_period = read_c_string(&mut cursor)?;
cursor.read_exact(&mut u8_buf)?;
let replace_if_present_flag = u8_buf[0];
cursor.read_exact(&mut u8_buf)?;
let data_coding = u8_buf[0];
cursor.read_exact(&mut u8_buf)?;
let sm_default_msg_id = u8_buf[0];
let mut optional_params = Vec::new();
while let Some(tlv) = Tlv::decode(&mut cursor)? {
optional_params.push(tlv);
}
Ok(Self {
sequence_number,
service_type,
source_addr_ton,
source_addr_npi,
source_addr,
message_id,
priority_flag,
schedule_delivery_time,
validity_period,
replace_if_present_flag,
data_coding,
sm_default_msg_id,
optional_params,
})
}
}