1use rusmpp_macros::Rusmpp;
2
3use crate::{
4 encode::Length,
5 pdus::owned::Pdu,
6 tlvs::{
7 TlvTag,
8 owned::{MessageSubmissionRequestTlvValue, Tlv},
9 },
10 types::owned::{COctetString, EmptyOrFullCOctetString, OctetString},
11 values::{owned::*, *},
12};
13
14#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Rusmpp)]
17#[rusmpp(decode = owned, test = skip)]
18#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
19#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
20#[cfg_attr(feature = "serde-deserialize-unchecked", derive(::serde::Deserialize))]
21pub struct SubmitSm {
22 pub service_type: ServiceType,
32 pub source_addr_ton: Ton,
34 pub source_addr_npi: Npi,
36 pub source_addr: COctetString<1, 21>,
38 pub dest_addr_ton: Ton,
40 pub dest_addr_npi: Npi,
42 pub destination_addr: COctetString<1, 21>,
48 pub esm_class: EsmClass,
51 pub protocol_id: u8,
54 pub priority_flag: PriorityFlag,
56 pub schedule_delivery_time: EmptyOrFullCOctetString<17>,
60 pub validity_period: EmptyOrFullCOctetString<17>,
66 pub registered_delivery: RegisteredDelivery,
69 pub replace_if_present_flag: ReplaceIfPresentFlag,
71 pub data_coding: DataCoding,
73 pub sm_default_msg_id: u8,
76 sm_length: u8,
78 #[rusmpp(length = sm_length)]
86 short_message: OctetString<0, 255>,
87 #[rusmpp(length = "unchecked")]
89 tlvs: alloc::vec::Vec<Tlv>,
90}
91
92impl SubmitSm {
93 #[allow(clippy::too_many_arguments)]
94 pub fn new(
95 service_type: ServiceType,
96 source_addr_ton: Ton,
97 source_addr_npi: Npi,
98 source_addr: COctetString<1, 21>,
99 dest_addr_ton: Ton,
100 dest_addr_npi: Npi,
101 destination_addr: COctetString<1, 21>,
102 esm_class: EsmClass,
103 protocol_id: u8,
104 priority_flag: PriorityFlag,
105 schedule_delivery_time: EmptyOrFullCOctetString<17>,
106 validity_period: EmptyOrFullCOctetString<17>,
107 registered_delivery: RegisteredDelivery,
108 replace_if_present_flag: ReplaceIfPresentFlag,
109 data_coding: DataCoding,
110 sm_default_msg_id: u8,
111 short_message: OctetString<0, 255>,
112 tlvs: alloc::vec::Vec<impl Into<MessageSubmissionRequestTlvValue>>,
113 ) -> Self {
114 let tlvs = tlvs.into_iter().map(Into::into).map(From::from).collect();
115
116 let sm_length = short_message.length() as u8;
117
118 let mut submit_sm = Self {
119 service_type,
120 source_addr_ton,
121 source_addr_npi,
122 source_addr,
123 dest_addr_ton,
124 dest_addr_npi,
125 destination_addr,
126 esm_class,
127 protocol_id,
128 priority_flag,
129 schedule_delivery_time,
130 validity_period,
131 registered_delivery,
132 replace_if_present_flag,
133 data_coding,
134 sm_default_msg_id,
135 sm_length,
136 short_message,
137 tlvs,
138 };
139
140 submit_sm.clear_short_message_if_message_payload_exists();
141
142 submit_sm
143 }
144
145 pub fn sm_length(&self) -> u8 {
146 self.sm_length
147 }
148
149 pub fn short_message(&self) -> &OctetString<0, 255> {
150 &self.short_message
151 }
152
153 pub fn set_short_message(&mut self, short_message: OctetString<0, 255>) -> bool {
158 self.short_message = short_message;
159 self.sm_length = self.short_message.length() as u8;
160
161 !self.clear_short_message_if_message_payload_exists()
162 }
163
164 pub fn tlvs(&self) -> &[Tlv] {
165 &self.tlvs
166 }
167
168 pub fn set_tlvs(&mut self, tlvs: alloc::vec::Vec<impl Into<MessageSubmissionRequestTlvValue>>) {
169 self.tlvs = tlvs.into_iter().map(Into::into).map(From::from).collect();
170
171 self.clear_short_message_if_message_payload_exists();
172 }
173
174 pub fn clear_tlvs(&mut self) {
175 self.tlvs.clear();
176 }
177
178 pub fn push_tlv(&mut self, tlv: impl Into<MessageSubmissionRequestTlvValue>) {
179 self.tlvs.push(Tlv::from(tlv.into()));
180
181 self.clear_short_message_if_message_payload_exists();
182 }
183
184 fn clear_short_message_if_message_payload_exists(&mut self) -> bool {
187 let message_payload_exists = self
188 .tlvs
189 .iter()
190 .any(|value| matches!(value.tag(), TlvTag::MessagePayload));
191
192 if message_payload_exists {
193 self.short_message = OctetString::empty();
194 self.sm_length = 0;
195
196 return true;
197 };
198
199 false
200 }
201
202 pub fn builder() -> SubmitSmBuilder {
203 SubmitSmBuilder::new()
204 }
205}
206
207impl From<SubmitSm> for Pdu {
208 fn from(value: SubmitSm) -> Self {
209 Self::SubmitSm(value)
210 }
211}
212
213#[derive(Debug, Default)]
214pub struct SubmitSmBuilder {
215 inner: SubmitSm,
216}
217
218impl SubmitSmBuilder {
219 pub fn new() -> Self {
220 Self::default()
221 }
222
223 pub fn service_type(mut self, service_type: ServiceType) -> Self {
224 self.inner.service_type = service_type;
225 self
226 }
227
228 pub fn source_addr_ton(mut self, source_addr_ton: Ton) -> Self {
229 self.inner.source_addr_ton = source_addr_ton;
230 self
231 }
232
233 pub fn source_addr_npi(mut self, source_addr_npi: Npi) -> Self {
234 self.inner.source_addr_npi = source_addr_npi;
235 self
236 }
237
238 pub fn source_addr(mut self, source_addr: COctetString<1, 21>) -> Self {
239 self.inner.source_addr = source_addr;
240 self
241 }
242
243 pub fn dest_addr_ton(mut self, dest_addr_ton: Ton) -> Self {
244 self.inner.dest_addr_ton = dest_addr_ton;
245 self
246 }
247
248 pub fn dest_addr_npi(mut self, dest_addr_npi: Npi) -> Self {
249 self.inner.dest_addr_npi = dest_addr_npi;
250 self
251 }
252
253 pub fn destination_addr(mut self, destination_addr: COctetString<1, 21>) -> Self {
254 self.inner.destination_addr = destination_addr;
255 self
256 }
257
258 pub fn esm_class(mut self, esm_class: EsmClass) -> Self {
259 self.inner.esm_class = esm_class;
260 self
261 }
262
263 pub fn protocol_id(mut self, protocol_id: u8) -> Self {
264 self.inner.protocol_id = protocol_id;
265 self
266 }
267
268 pub fn priority_flag(mut self, priority_flag: PriorityFlag) -> Self {
269 self.inner.priority_flag = priority_flag;
270 self
271 }
272
273 pub fn schedule_delivery_time(
274 mut self,
275 schedule_delivery_time: EmptyOrFullCOctetString<17>,
276 ) -> Self {
277 self.inner.schedule_delivery_time = schedule_delivery_time;
278 self
279 }
280
281 pub fn validity_period(mut self, validity_period: EmptyOrFullCOctetString<17>) -> Self {
282 self.inner.validity_period = validity_period;
283 self
284 }
285
286 pub fn registered_delivery(mut self, registered_delivery: RegisteredDelivery) -> Self {
287 self.inner.registered_delivery = registered_delivery;
288 self
289 }
290
291 pub fn replace_if_present_flag(
292 mut self,
293 replace_if_present_flag: ReplaceIfPresentFlag,
294 ) -> Self {
295 self.inner.replace_if_present_flag = replace_if_present_flag;
296 self
297 }
298
299 pub fn data_coding(mut self, data_coding: DataCoding) -> Self {
300 self.inner.data_coding = data_coding;
301 self
302 }
303
304 pub fn sm_default_msg_id(mut self, sm_default_msg_id: u8) -> Self {
305 self.inner.sm_default_msg_id = sm_default_msg_id;
306 self
307 }
308
309 pub fn short_message(mut self, short_message: OctetString<0, 255>) -> Self {
310 self.inner.set_short_message(short_message);
311 self
312 }
313
314 pub fn tlvs(
315 mut self,
316 tlvs: alloc::vec::Vec<impl Into<MessageSubmissionRequestTlvValue>>,
317 ) -> Self {
318 self.inner.set_tlvs(tlvs);
319 self
320 }
321
322 pub fn clear_tlvs(mut self) -> Self {
323 self.inner.clear_tlvs();
324 self
325 }
326
327 pub fn push_tlv(mut self, tlv: impl Into<MessageSubmissionRequestTlvValue>) -> Self {
328 self.inner.push_tlv(tlv);
329 self
330 }
331
332 pub fn build(self) -> SubmitSm {
333 self.inner
334 }
335}
336
337#[cfg(test)]
338mod tests {
339 use std::str::FromStr;
340
341 use crate::{tests::TestInstance, types::owned::AnyOctetString};
342
343 use super::*;
344
345 impl TestInstance for SubmitSm {
346 fn instances() -> alloc::vec::Vec<Self> {
347 alloc::vec![
348 Self::default(),
349 Self::builder()
350 .service_type(ServiceType::new(
351 GenericServiceType::CellularMessaging.into(),
352 ))
353 .source_addr_ton(Ton::International)
354 .source_addr_npi(Npi::Isdn)
355 .source_addr(COctetString::from_str("Source Address").unwrap())
356 .dest_addr_ton(Ton::International)
357 .dest_addr_npi(Npi::Isdn)
358 .destination_addr(COctetString::from_str("Destination Address").unwrap())
359 .esm_class(EsmClass::new(
360 MessagingMode::StoreAndForward,
361 MessageType::ShortMessageContainsMCDeliveryReceipt,
362 Ansi41Specific::ShortMessageContainsDeliveryAcknowledgement,
363 GsmFeatures::SetUdhiAndReplyPath,
364 ))
365 .protocol_id(0)
366 .priority_flag(PriorityFlag::from(PriorityFlagType::from(Ansi136::Bulk)))
367 .schedule_delivery_time(
368 EmptyOrFullCOctetString::new(b"2023-09-01T12:00\0").unwrap(),
369 )
370 .validity_period(EmptyOrFullCOctetString::from_str("2023-10-01T12:00").unwrap())
371 .registered_delivery(RegisteredDelivery::request_all())
372 .replace_if_present_flag(ReplaceIfPresentFlag::Replace)
373 .data_coding(DataCoding::Ksc5601)
374 .sm_default_msg_id(69)
375 .short_message(OctetString::new(b"Short Message").unwrap())
376 .build(),
377 Self::builder()
378 .service_type(ServiceType::new(
379 GenericServiceType::CellularMessaging.into(),
380 ))
381 .source_addr_ton(Ton::International)
382 .source_addr_npi(Npi::Isdn)
383 .source_addr(COctetString::new(b"Source Address\0").unwrap())
384 .dest_addr_ton(Ton::International)
385 .dest_addr_npi(Npi::Isdn)
386 .destination_addr(COctetString::new(b"Destination Address\0").unwrap())
387 .esm_class(EsmClass::new(
388 MessagingMode::Default,
389 MessageType::ShortMessageContainsIntermediateDeliveryNotification,
390 Ansi41Specific::ShortMessageContainsUserAcknowledgment,
391 GsmFeatures::SetUdhiAndReplyPath,
392 ))
393 .protocol_id(0)
394 .priority_flag(PriorityFlag::from(PriorityFlagType::from(
395 Ansi136::VeryUrgent,
396 )))
397 .schedule_delivery_time(
398 EmptyOrFullCOctetString::new(b"2023-09-01T12:01\0").unwrap(),
399 )
400 .validity_period(EmptyOrFullCOctetString::from_str("2023-10-01T12:20").unwrap())
401 .registered_delivery(RegisteredDelivery::request_all())
402 .replace_if_present_flag(ReplaceIfPresentFlag::DoNotReplace)
403 .data_coding(DataCoding::Jis)
404 .sm_default_msg_id(96)
405 .short_message(OctetString::new(b"Short Message").unwrap())
406 .tlvs(alloc::vec![
407 MessageSubmissionRequestTlvValue::MessagePayload(MessagePayload::new(
408 AnyOctetString::new(b"Message Payload")
409 ),)
410 ])
411 .build(),
412 Self::builder()
413 .short_message(OctetString::new(b"Short Message").unwrap())
414 .tlvs(alloc::vec![
415 MessageSubmissionRequestTlvValue::MessagePayload(MessagePayload::new(
416 AnyOctetString::new(b"Message Payload"),
417 )),
418 MessageSubmissionRequestTlvValue::UserResponseCode(3),
419 MessageSubmissionRequestTlvValue::DestBearerType(BearerType::FlexReFlex),
420 MessageSubmissionRequestTlvValue::SourceSubaddress(Subaddress::new(
421 SubaddressTag::NsapOdd,
422 OctetString::from_str("Subaddress :D").unwrap(),
423 )),
424 ])
425 .build(),
426 ]
427 }
428 }
429
430 #[test]
431 fn encode_decode() {
432 crate::tests::owned::encode_decode_with_length_test_instances::<SubmitSm>();
433 }
434
435 #[test]
436 fn short_message_length() {
437 let short_message = OctetString::new(b"Short Message").unwrap();
438
439 let submit_sm = SubmitSm::builder()
440 .short_message(short_message.clone())
441 .build();
442
443 assert_eq!(submit_sm.short_message(), &short_message);
444 assert_eq!(submit_sm.sm_length(), short_message.length() as u8);
445 }
446
447 #[test]
448 fn short_message_override() {
449 let short_message_1 = OctetString::new(b"Short Message 101").unwrap();
450 let short_message_2 = OctetString::new(b"Short Message 2").unwrap();
451
452 let submit_sm = SubmitSm::builder()
453 .short_message(short_message_1)
454 .short_message(short_message_2.clone())
455 .build();
456
457 assert_eq!(submit_sm.short_message(), &short_message_2);
458 assert_eq!(submit_sm.sm_length(), short_message_2.length() as u8);
459 }
460
461 #[test]
462 fn message_payload_suppresses_short_message() {
463 let short_message = OctetString::new(b"Short Message").unwrap();
464 let message_payload = MessagePayload::new(AnyOctetString::new(b"Message Payload"));
465
466 let submit_sm = SubmitSm::builder()
468 .short_message(short_message.clone())
469 .push_tlv(MessageSubmissionRequestTlvValue::MessagePayload(
470 message_payload.clone(),
471 ))
472 .build();
473
474 assert_eq!(submit_sm.short_message(), &OctetString::empty());
475 assert_eq!(submit_sm.sm_length(), 0);
476
477 let submit_sm = SubmitSm::builder()
479 .short_message(short_message.clone())
480 .tlvs(alloc::vec![
481 MessageSubmissionRequestTlvValue::MessagePayload(message_payload.clone(),)
482 ])
483 .build();
484
485 assert_eq!(submit_sm.short_message(), &OctetString::empty());
486 assert_eq!(submit_sm.sm_length(), 0);
487
488 let submit_sm = SubmitSm::builder()
491 .short_message(short_message.clone())
492 .push_tlv(MessageSubmissionRequestTlvValue::MessagePayload(
493 message_payload.clone(),
494 ))
495 .short_message(short_message.clone())
496 .build();
497
498 assert_eq!(submit_sm.short_message(), &OctetString::empty());
499 assert_eq!(submit_sm.sm_length(), 0);
500
501 let submit_sm = SubmitSm::builder()
503 .short_message(short_message.clone())
504 .tlvs(alloc::vec![
505 MessageSubmissionRequestTlvValue::MessagePayload(message_payload.clone(),)
506 ])
507 .short_message(short_message.clone())
508 .build();
509
510 assert_eq!(submit_sm.short_message(), &OctetString::empty());
511 assert_eq!(submit_sm.sm_length(), 0);
512
513 let submit_sm = SubmitSm::builder()
515 .push_tlv(MessageSubmissionRequestTlvValue::MessagePayload(
516 message_payload.clone(),
517 ))
518 .clear_tlvs()
519 .short_message(short_message.clone())
520 .build();
521
522 assert_eq!(submit_sm.short_message(), &short_message);
523 assert_eq!(submit_sm.sm_length(), short_message.length() as u8);
524 }
525}