1use rusmpp_macros::Rusmpp;
2
3use crate::{
4 encode::Length,
5 pdus::owned::Pdu,
6 tlvs::owned::{Tlv, TlvValue},
7 types::owned::{COctetString, EmptyOrFullCOctetString, OctetString},
8 values::{owned::*, *},
9};
10
11#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Rusmpp)]
18#[rusmpp(decode = owned, test = skip)]
19#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
20#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
21#[cfg_attr(feature = "serde-deserialize-unchecked", derive(::serde::Deserialize))]
22pub struct ReplaceSm {
23 pub message_id: COctetString<1, 65>,
30 pub source_addr_ton: Ton,
36 pub source_addr_npi: Npi,
41 pub source_addr: COctetString<1, 21>,
44 pub schedule_delivery_time: EmptyOrFullCOctetString<17>,
48 pub validity_period: EmptyOrFullCOctetString<17>,
54 pub registered_delivery: RegisteredDelivery,
58 pub sm_default_msg_id: u8,
64 sm_length: u8,
66 #[rusmpp(length = sm_length)]
76 short_message: OctetString<0, 255>,
77 #[rusmpp(length = "checked")]
79 message_payload: Option<Tlv>,
80}
81
82impl ReplaceSm {
83 #[allow(clippy::too_many_arguments)]
84 pub fn new(
85 message_id: COctetString<1, 65>,
86 source_addr_ton: Ton,
87 source_addr_npi: Npi,
88 source_addr: COctetString<1, 21>,
89 schedule_delivery_time: EmptyOrFullCOctetString<17>,
90 validity_period: EmptyOrFullCOctetString<17>,
91 registered_delivery: RegisteredDelivery,
92 sm_default_msg_id: u8,
93 short_message: OctetString<0, 255>,
94 message_payload: Option<MessagePayload>,
95 ) -> Self {
96 let message_payload = message_payload
97 .map(TlvValue::MessagePayload)
98 .map(From::from);
99
100 let sm_length = short_message.length() as u8;
101
102 let mut replace_sm = Self {
103 message_id,
104 source_addr_ton,
105 source_addr_npi,
106 source_addr,
107 schedule_delivery_time,
108 validity_period,
109 registered_delivery,
110 sm_default_msg_id,
111 sm_length,
112 short_message,
113 message_payload,
114 };
115
116 replace_sm.clear_short_message_if_message_payload_exists();
117
118 replace_sm
119 }
120
121 pub const fn sm_length(&self) -> u8 {
122 self.sm_length
123 }
124
125 pub fn short_message(&self) -> &OctetString<0, 255> {
126 &self.short_message
127 }
128
129 pub fn set_short_message(&mut self, short_message: OctetString<0, 255>) -> bool {
134 self.sm_length = short_message.length() as u8;
135 self.short_message = short_message;
136
137 !self.clear_short_message_if_message_payload_exists()
138 }
139
140 pub const fn message_payload_tlv(&self) -> Option<&Tlv> {
141 self.message_payload.as_ref()
142 }
143
144 pub fn message_payload(&self) -> Option<&MessagePayload> {
145 self.message_payload_tlv()
146 .and_then(|tlv| match tlv.value() {
147 Some(TlvValue::MessagePayload(value)) => Some(value),
148 _ => None,
149 })
150 }
151
152 pub fn set_message_payload(&mut self, message_payload: Option<MessagePayload>) {
155 self.message_payload = message_payload
156 .map(TlvValue::MessagePayload)
157 .map(From::from);
158
159 self.clear_short_message_if_message_payload_exists();
160 }
161
162 fn clear_short_message_if_message_payload_exists(&mut self) -> bool {
165 if self.message_payload.is_some() {
166 self.short_message = OctetString::empty();
167 self.sm_length = 0;
168
169 return true;
170 };
171
172 false
173 }
174
175 pub fn builder() -> ReplaceSmBuilder {
176 ReplaceSmBuilder::new()
177 }
178}
179
180impl From<ReplaceSm> for Pdu {
181 fn from(value: ReplaceSm) -> Self {
182 Self::ReplaceSm(value)
183 }
184}
185
186#[derive(Debug, Default)]
187pub struct ReplaceSmBuilder {
188 inner: ReplaceSm,
189}
190
191impl ReplaceSmBuilder {
192 pub fn new() -> Self {
193 Self::default()
194 }
195
196 pub fn message_id(mut self, message_id: COctetString<1, 65>) -> Self {
197 self.inner.message_id = message_id;
198 self
199 }
200
201 pub fn source_addr_ton(mut self, source_addr_ton: Ton) -> Self {
202 self.inner.source_addr_ton = source_addr_ton;
203 self
204 }
205
206 pub fn source_addr_npi(mut self, source_addr_npi: Npi) -> Self {
207 self.inner.source_addr_npi = source_addr_npi;
208 self
209 }
210
211 pub fn source_addr(mut self, source_addr: COctetString<1, 21>) -> Self {
212 self.inner.source_addr = source_addr;
213 self
214 }
215
216 pub fn schedule_delivery_time(
217 mut self,
218 schedule_delivery_time: EmptyOrFullCOctetString<17>,
219 ) -> Self {
220 self.inner.schedule_delivery_time = schedule_delivery_time;
221 self
222 }
223
224 pub fn validity_period(mut self, validity_period: EmptyOrFullCOctetString<17>) -> Self {
225 self.inner.validity_period = validity_period;
226 self
227 }
228
229 pub fn registered_delivery(mut self, registered_delivery: RegisteredDelivery) -> Self {
230 self.inner.registered_delivery = registered_delivery;
231 self
232 }
233
234 pub fn sm_default_msg_id(mut self, sm_default_msg_id: u8) -> Self {
235 self.inner.sm_default_msg_id = sm_default_msg_id;
236 self
237 }
238
239 pub fn short_message(mut self, short_message: OctetString<0, 255>) -> Self {
240 self.inner.set_short_message(short_message);
241 self
242 }
243
244 pub fn message_payload(mut self, message_payload: Option<MessagePayload>) -> Self {
245 self.inner.set_message_payload(message_payload);
246 self
247 }
248
249 pub fn build(self) -> ReplaceSm {
250 self.inner
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 use std::str::FromStr;
257
258 use crate::{tests::TestInstance, types::owned::AnyOctetString};
259
260 use super::*;
261
262 impl TestInstance for ReplaceSm {
263 fn instances() -> alloc::vec::Vec<Self> {
264 alloc::vec![
265 Self::default(),
266 Self::builder()
267 .message_id(COctetString::from_str("123456789012345678901234").unwrap())
268 .source_addr_ton(Ton::International)
269 .source_addr_npi(Npi::Isdn)
270 .source_addr(COctetString::from_str("Source Addr").unwrap())
271 .schedule_delivery_time(
272 EmptyOrFullCOctetString::new(b"2023-10-01T12:00\0").unwrap(),
273 )
274 .validity_period(EmptyOrFullCOctetString::new(b"2023-10-01T12:00\0").unwrap())
275 .registered_delivery(RegisteredDelivery::default())
276 .sm_default_msg_id(0)
277 .short_message(OctetString::new(b"Short Message").unwrap())
278 .build(),
279 Self::builder()
280 .message_id(COctetString::from_str("123456789012345678901234").unwrap())
281 .source_addr_ton(Ton::International)
282 .source_addr_npi(Npi::Isdn)
283 .source_addr(COctetString::from_str("Source Addr").unwrap())
284 .schedule_delivery_time(
285 EmptyOrFullCOctetString::new(b"2023-10-01T12:00\0").unwrap(),
286 )
287 .validity_period(EmptyOrFullCOctetString::new(b"2023-10-01T12:00\0").unwrap())
288 .registered_delivery(RegisteredDelivery::default())
289 .sm_default_msg_id(0)
290 .message_payload(Some(MessagePayload::new(AnyOctetString::new(
291 b"Message Payload",
292 ))))
293 .build(),
294 Self::builder()
295 .validity_period(EmptyOrFullCOctetString::new(b"2023-10-01T12:00\0").unwrap())
296 .short_message(OctetString::new(b"Short Message").unwrap())
297 .message_payload(Some(MessagePayload::new(AnyOctetString::new(
298 b"Message Payload",
299 ))))
300 .build(),
301 ]
302 }
303 }
304
305 #[test]
306 fn encode_decode() {
307 crate::tests::owned::encode_decode_with_length_test_instances::<ReplaceSm>();
308 }
309
310 #[test]
311 fn short_message_length() {
312 let short_message = OctetString::new(b"Short Message").unwrap();
313
314 let submit_sm = ReplaceSm::builder()
315 .short_message(short_message.clone())
316 .build();
317
318 assert_eq!(submit_sm.short_message(), &short_message);
319 assert_eq!(submit_sm.sm_length(), short_message.length() as u8);
320 }
321
322 #[test]
323 fn short_message_override() {
324 let short_message_1 = OctetString::new(b"Short Message 101").unwrap();
325 let short_message_2 = OctetString::new(b"Short Message 2").unwrap();
326
327 let submit_sm = ReplaceSm::builder()
328 .short_message(short_message_1)
329 .short_message(short_message_2.clone())
330 .build();
331
332 assert_eq!(submit_sm.short_message(), &short_message_2);
333 assert_eq!(submit_sm.sm_length(), short_message_2.length() as u8);
334 }
335
336 #[test]
337 fn message_payload_suppresses_short_message() {
338 let short_message = OctetString::new(b"Short Message").unwrap();
339 let message_payload = MessagePayload::new(AnyOctetString::new(b"Message Payload"));
340
341 let replace_sm = ReplaceSm::builder()
343 .short_message(short_message.clone())
344 .message_payload(Some(message_payload.clone()))
345 .build();
346
347 assert_eq!(replace_sm.short_message(), &OctetString::empty());
348 assert_eq!(replace_sm.sm_length(), 0);
349
350 let submit_sm = ReplaceSm::builder()
352 .short_message(short_message.clone())
353 .message_payload(Some(message_payload.clone()))
354 .short_message(short_message.clone())
355 .build();
356
357 assert_eq!(submit_sm.short_message(), &OctetString::empty());
358 assert_eq!(submit_sm.sm_length(), 0);
359
360 let submit_sm = ReplaceSm::builder()
362 .message_payload(Some(message_payload.clone()))
363 .message_payload(None)
364 .short_message(short_message.clone())
365 .build();
366
367 assert_eq!(submit_sm.short_message(), &short_message);
368 assert_eq!(submit_sm.sm_length(), short_message.length() as u8);
369 }
370}