1use rusmpp_macros::Rusmpp;
2
3use crate::{
4 encode::Length,
5 pdus::borrowed::Pdu,
6 tlvs::{
7 TlvTag,
8 borrowed::{MessageSubmissionRequestTlvValue, Tlv},
9 },
10 types::borrowed::{COctetString, EmptyOrFullCOctetString, OctetString},
11 values::{borrowed::*, *},
12};
13
14#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Rusmpp)]
15#[rusmpp(decode = borrowed, test = skip)]
16#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
17#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
18pub struct SubmitMulti<'a, const N: usize> {
19 pub service_type: ServiceType<'a>,
28 pub source_addr_ton: Ton,
32 pub source_addr_npi: Npi,
36 pub source_addr: COctetString<'a, 1, 21>,
40 number_of_dests: u8,
48 #[rusmpp(count = number_of_dests)]
50 #[cfg_attr(feature = "arbitrary", arbitrary(default))]
51 dest_address: heapless::vec::Vec<DestAddress<'a>, N>,
52 pub esm_class: EsmClass,
54 pub protocol_id: u8,
58 pub priority_flag: PriorityFlag,
60 pub schedule_delivery_time: EmptyOrFullCOctetString<'a, 17>,
64 pub validity_period: EmptyOrFullCOctetString<'a, 17>,
70 pub registered_delivery: RegisteredDelivery,
73 pub replace_if_present_flag: ReplaceIfPresentFlag,
76 pub data_coding: DataCoding,
78 pub sm_default_msg_id: u8,
83 sm_length: u8,
85 #[rusmpp(length = sm_length)]
97 short_message: OctetString<'a, 0, 255>,
98 #[rusmpp(length = "unchecked")]
100 #[cfg_attr(feature = "arbitrary", arbitrary(default))]
101 tlvs: heapless::vec::Vec<Tlv<'a>, N>,
102}
103
104impl<'a, const N: usize> SubmitMulti<'a, N> {
105 #[allow(clippy::too_many_arguments)]
106 pub fn new(
107 service_type: ServiceType<'a>,
108 source_addr_ton: Ton,
109 source_addr_npi: Npi,
110 source_addr: COctetString<'a, 1, 21>,
111 dest_address: heapless::vec::Vec<DestAddress<'a>, N>,
112 esm_class: EsmClass,
113 protocol_id: u8,
114 priority_flag: PriorityFlag,
115 schedule_delivery_time: EmptyOrFullCOctetString<'a, 17>,
116 validity_period: EmptyOrFullCOctetString<'a, 17>,
117 registered_delivery: RegisteredDelivery,
118 replace_if_present_flag: ReplaceIfPresentFlag,
119 data_coding: DataCoding,
120 sm_default_msg_id: u8,
121 short_message: OctetString<'a, 0, 255>,
122 tlvs: heapless::vec::Vec<impl Into<MessageSubmissionRequestTlvValue<'a>>, N>,
123 ) -> Self {
124 let sm_length = short_message.length() as u8;
125 let number_of_dests = dest_address.len() as u8;
126
127 let tlvs = tlvs.into_iter().map(Into::into).map(From::from).collect();
128
129 let mut submit_multi = Self {
130 service_type,
131 source_addr_ton,
132 source_addr_npi,
133 source_addr,
134 number_of_dests,
135 dest_address,
136 esm_class,
137 protocol_id,
138 priority_flag,
139 schedule_delivery_time,
140 validity_period,
141 registered_delivery,
142 replace_if_present_flag,
143 data_coding,
144 sm_default_msg_id,
145 sm_length,
146 short_message,
147 tlvs,
148 };
149
150 submit_multi.clear_short_message_if_message_payload_exists();
151
152 submit_multi
153 }
154
155 pub const fn number_of_dests(&self) -> u8 {
156 self.number_of_dests
157 }
158
159 pub fn dest_address(&'_ self) -> &'_ [DestAddress<'_>] {
160 &self.dest_address
161 }
162
163 pub fn set_dest_address(&mut self, dest_address: heapless::vec::Vec<DestAddress<'a>, N>) {
164 self.dest_address = dest_address;
165 self.number_of_dests = self.dest_address.len() as u8;
166 }
167
168 pub fn push_dest_address(
169 &mut self,
170 dest_address: DestAddress<'a>,
171 ) -> Result<(), DestAddress<'a>> {
172 self.dest_address.push(dest_address)?;
173 self.number_of_dests = self.dest_address.len() as u8;
174
175 Ok(())
176 }
177
178 pub fn clear_dest_address(&mut self) {
179 self.dest_address.clear();
180 self.number_of_dests = self.dest_address.len() as u8;
181 }
182
183 pub const fn sm_length(&self) -> u8 {
184 self.sm_length
185 }
186
187 pub const fn short_message(&self) -> &OctetString<'a, 0, 255> {
188 &self.short_message
189 }
190
191 pub fn set_short_message(&mut self, short_message: OctetString<'a, 0, 255>) -> bool {
196 self.short_message = short_message;
197 self.sm_length = self.short_message.length() as u8;
198
199 !self.clear_short_message_if_message_payload_exists()
200 }
201
202 pub fn tlvs(&'_ self) -> &'_ [Tlv<'_>] {
203 &self.tlvs
204 }
205
206 pub fn set_tlvs(
207 &mut self,
208 tlvs: heapless::vec::Vec<impl Into<MessageSubmissionRequestTlvValue<'a>>, N>,
209 ) {
210 self.tlvs = tlvs.into_iter().map(Into::into).map(From::from).collect();
211
212 self.clear_short_message_if_message_payload_exists();
213 }
214
215 pub fn clear_tlvs(&mut self) {
216 self.tlvs.clear();
217 }
218
219 pub fn push_tlv(
220 &mut self,
221 tlv: impl Into<MessageSubmissionRequestTlvValue<'a>>,
222 ) -> Result<(), Tlv<'a>> {
223 self.tlvs.push(Tlv::from(tlv.into()))?;
224
225 self.clear_short_message_if_message_payload_exists();
226
227 Ok(())
228 }
229
230 fn clear_short_message_if_message_payload_exists(&mut self) -> bool {
233 let message_payload_exists = self
234 .tlvs
235 .iter()
236 .any(|value| matches!(value.tag(), TlvTag::MessagePayload));
237
238 if message_payload_exists {
239 self.short_message = OctetString::empty();
240 self.sm_length = 0;
241
242 return true;
243 };
244
245 false
246 }
247
248 pub fn builder() -> SubmitMultiBuilder<'a, N> {
249 SubmitMultiBuilder::new()
250 }
251}
252
253impl<'a, const N: usize> From<SubmitMulti<'a, N>> for Pdu<'a, N> {
254 fn from(value: SubmitMulti<'a, N>) -> Self {
255 Self::SubmitMulti(value)
256 }
257}
258
259#[derive(Debug, Default)]
260pub struct SubmitMultiBuilder<'a, const N: usize> {
261 inner: SubmitMulti<'a, N>,
262}
263
264impl<'a, const N: usize> SubmitMultiBuilder<'a, N> {
265 pub fn new() -> Self {
266 Default::default()
267 }
268
269 pub fn service_type(mut self, service_type: ServiceType<'a>) -> Self {
270 self.inner.service_type = service_type;
271 self
272 }
273
274 pub fn source_addr_ton(mut self, source_addr_ton: Ton) -> Self {
275 self.inner.source_addr_ton = source_addr_ton;
276 self
277 }
278
279 pub fn source_addr_npi(mut self, source_addr_npi: Npi) -> Self {
280 self.inner.source_addr_npi = source_addr_npi;
281 self
282 }
283
284 pub fn source_addr(mut self, source_addr: COctetString<'a, 1, 21>) -> Self {
285 self.inner.source_addr = source_addr;
286 self
287 }
288
289 pub fn dest_address(mut self, dest_address: heapless::vec::Vec<DestAddress<'a>, N>) -> Self {
290 self.inner.set_dest_address(dest_address);
291 self
292 }
293
294 pub fn push_dest_address(
295 mut self,
296 dest_address: DestAddress<'a>,
297 ) -> Result<Self, DestAddress<'a>> {
298 self.inner.push_dest_address(dest_address)?;
299 Ok(self)
300 }
301
302 pub fn clear_dest_address(mut self) -> Self {
303 self.inner.clear_dest_address();
304 self
305 }
306
307 pub fn esm_class(mut self, esm_class: EsmClass) -> Self {
308 self.inner.esm_class = esm_class;
309 self
310 }
311
312 pub fn protocol_id(mut self, protocol_id: u8) -> Self {
313 self.inner.protocol_id = protocol_id;
314 self
315 }
316
317 pub fn priority_flag(mut self, priority_flag: PriorityFlag) -> Self {
318 self.inner.priority_flag = priority_flag;
319 self
320 }
321
322 pub fn schedule_delivery_time(
323 mut self,
324 schedule_delivery_time: EmptyOrFullCOctetString<'a, 17>,
325 ) -> Self {
326 self.inner.schedule_delivery_time = schedule_delivery_time;
327 self
328 }
329
330 pub fn validity_period(mut self, validity_period: EmptyOrFullCOctetString<'a, 17>) -> Self {
331 self.inner.validity_period = validity_period;
332 self
333 }
334
335 pub fn registered_delivery(mut self, registered_delivery: RegisteredDelivery) -> Self {
336 self.inner.registered_delivery = registered_delivery;
337 self
338 }
339
340 pub fn replace_if_present_flag(
341 mut self,
342 replace_if_present_flag: ReplaceIfPresentFlag,
343 ) -> Self {
344 self.inner.replace_if_present_flag = replace_if_present_flag;
345 self
346 }
347
348 pub fn data_coding(mut self, data_coding: DataCoding) -> Self {
349 self.inner.data_coding = data_coding;
350 self
351 }
352
353 pub fn sm_default_msg_id(mut self, sm_default_msg_id: u8) -> Self {
354 self.inner.sm_default_msg_id = sm_default_msg_id;
355 self
356 }
357
358 pub fn short_message(mut self, short_message: OctetString<'a, 0, 255>) -> Self {
359 self.inner.set_short_message(short_message);
360 self
361 }
362
363 pub fn tlvs(
364 mut self,
365 tlvs: heapless::vec::Vec<impl Into<MessageSubmissionRequestTlvValue<'a>>, N>,
366 ) -> Self {
367 self.inner.set_tlvs(tlvs);
368 self
369 }
370
371 pub fn clear_tlvs(mut self) -> Self {
372 self.inner.clear_tlvs();
373 self
374 }
375
376 pub fn push_tlv(
377 mut self,
378 tlv: impl Into<MessageSubmissionRequestTlvValue<'a>>,
379 ) -> Result<Self, Tlv<'a>> {
380 self.inner.push_tlv(tlv)?;
381 Ok(self)
382 }
383
384 pub fn build(self) -> SubmitMulti<'a, N> {
385 self.inner
386 }
387}
388
389#[cfg(test)]
390mod tests {
391 use crate::{tests::TestInstance, types::borrowed::AnyOctetString};
392
393 use super::*;
394
395 impl<const N: usize> TestInstance for SubmitMulti<'static, N> {
396 fn instances() -> alloc::vec::Vec<Self> {
397 alloc::vec![
398 Self::default(),
399 Self::builder()
400 .service_type(ServiceType::default())
401 .source_addr_ton(Ton::International)
402 .source_addr_npi(Npi::Isdn)
403 .source_addr(COctetString::new(b"Source Address\0").unwrap())
404 .esm_class(EsmClass::default())
405 .protocol_id(0)
406 .priority_flag(PriorityFlag::default())
407 .schedule_delivery_time(EmptyOrFullCOctetString::empty())
408 .validity_period(EmptyOrFullCOctetString::empty())
409 .registered_delivery(RegisteredDelivery::default())
410 .replace_if_present_flag(ReplaceIfPresentFlag::default())
411 .data_coding(DataCoding::default())
412 .sm_default_msg_id(0)
413 .short_message(OctetString::new(b"Short Message").unwrap())
414 .build(),
415 Self::builder()
416 .short_message(OctetString::new(b"Short Message").unwrap())
417 .push_tlv(MessageSubmissionRequestTlvValue::MessagePayload(
418 MessagePayload::new(AnyOctetString::new(b"Message Payload")),
419 ))
420 .unwrap()
421 .build(),
422 Self::builder()
423 .push_dest_address(DestAddress::SmeAddress(SmeAddress::new(
424 Ton::International,
425 Npi::Isdn,
426 COctetString::new(b"1234567890123456789\0").unwrap(),
427 )))
428 .unwrap()
429 .push_dest_address(DestAddress::DistributionListName(
430 DistributionListName::new(
431 COctetString::new(b"1234567890123456789\0").unwrap(),
432 ),
433 ))
434 .unwrap()
435 .short_message(OctetString::new(b"Short Message").unwrap())
436 .push_tlv(MessageSubmissionRequestTlvValue::MessagePayload(
437 MessagePayload::new(AnyOctetString::new(b"Message Payload")),
438 ))
439 .unwrap()
440 .push_tlv(MessageSubmissionRequestTlvValue::DestTelematicsId(16))
441 .unwrap()
442 .build(),
443 ]
444 }
445 }
446
447 #[test]
448 fn encode_decode() {
449 crate::tests::borrowed::encode_decode_with_length_test_instances::<SubmitMulti<'static, 16>>(
450 );
451 }
452
453 #[test]
454 fn short_message_length() {
455 let short_message = OctetString::new(b"Short Message").unwrap();
456
457 let submit_sm = SubmitMulti::<'static, 16>::builder()
458 .short_message(short_message.clone())
459 .build();
460
461 assert_eq!(submit_sm.short_message(), &short_message);
462 assert_eq!(submit_sm.sm_length(), short_message.length() as u8);
463 }
464
465 #[test]
466 fn short_message_override() {
467 let short_message_1 = OctetString::new(b"Short Message 101").unwrap();
468 let short_message_2 = OctetString::new(b"Short Message 2").unwrap();
469
470 let submit_sm = SubmitMulti::<'static, 16>::builder()
471 .short_message(short_message_1)
472 .short_message(short_message_2.clone())
473 .build();
474
475 assert_eq!(submit_sm.short_message(), &short_message_2);
476 assert_eq!(submit_sm.sm_length(), short_message_2.length() as u8);
477 }
478
479 #[test]
480 fn message_payload_suppresses_short_message() {
481 let short_message = OctetString::new(b"Short Message").unwrap();
482 let message_payload = MessagePayload::new(AnyOctetString::new(b"Message Payload"));
483
484 let submit_sm = SubmitMulti::<'static, 16>::builder()
486 .short_message(short_message.clone())
487 .push_tlv(MessageSubmissionRequestTlvValue::MessagePayload(
488 message_payload.clone(),
489 ))
490 .unwrap()
491 .build();
492
493 assert_eq!(submit_sm.short_message(), &OctetString::empty());
494 assert_eq!(submit_sm.sm_length(), 0);
495
496 let submit_sm = SubmitMulti::<'static, 16>::builder()
498 .short_message(short_message.clone())
499 .tlvs(
500 [MessageSubmissionRequestTlvValue::MessagePayload(
501 message_payload.clone(),
502 )]
503 .into(),
504 )
505 .build();
506
507 assert_eq!(submit_sm.short_message(), &OctetString::empty());
508 assert_eq!(submit_sm.sm_length(), 0);
509
510 let submit_sm = SubmitMulti::<'static, 16>::builder()
513 .short_message(short_message.clone())
514 .push_tlv(MessageSubmissionRequestTlvValue::MessagePayload(
515 message_payload.clone(),
516 ))
517 .unwrap()
518 .short_message(short_message.clone())
519 .build();
520
521 assert_eq!(submit_sm.short_message(), &OctetString::empty());
522 assert_eq!(submit_sm.sm_length(), 0);
523
524 let submit_multi = SubmitMulti::<'static, 16>::builder()
526 .short_message(short_message.clone())
527 .tlvs(
528 [MessageSubmissionRequestTlvValue::MessagePayload(
529 message_payload.clone(),
530 )]
531 .into(),
532 )
533 .short_message(short_message.clone())
534 .build();
535
536 assert_eq!(submit_multi.short_message(), &OctetString::empty());
537 assert_eq!(submit_multi.sm_length(), 0);
538
539 let submit_sm = SubmitMulti::<'static, 16>::builder()
541 .push_tlv(MessageSubmissionRequestTlvValue::MessagePayload(
542 message_payload.clone(),
543 ))
544 .unwrap()
545 .clear_tlvs()
546 .short_message(short_message.clone())
547 .build();
548
549 assert_eq!(submit_sm.short_message(), &short_message);
550 assert_eq!(submit_sm.sm_length(), short_message.length() as u8);
551 }
552
553 #[test]
554 fn count() {
555 let submit_multi = SubmitMulti::<'static, 16>::default();
556
557 assert_eq!(submit_multi.number_of_dests(), 0);
558 assert!(submit_multi.dest_address().is_empty());
559
560 let submit_sm = SubmitMulti::<'static, 16>::builder()
561 .dest_address(
562 [
563 DestAddress::SmeAddress(SmeAddress::new(
564 Ton::International,
565 Npi::Isdn,
566 COctetString::new(b"1234567890123456789\0").unwrap(),
567 )),
568 DestAddress::DistributionListName(DistributionListName::new(
569 COctetString::new(b"1234567890123456789\0").unwrap(),
570 )),
571 ]
572 .into(),
573 )
574 .build();
575
576 assert_eq!(submit_sm.number_of_dests(), 2);
577 assert_eq!(submit_sm.dest_address().len(), 2);
578
579 let submit_sm = SubmitMulti::<'static, 16>::builder()
580 .push_dest_address(DestAddress::SmeAddress(SmeAddress::new(
581 Ton::International,
582 Npi::Isdn,
583 COctetString::new(b"1234567890123456789\0").unwrap(),
584 )))
585 .unwrap()
586 .push_dest_address(DestAddress::DistributionListName(
587 DistributionListName::new(COctetString::new(b"1234567890123456789\0").unwrap()),
588 ))
589 .unwrap()
590 .build();
591
592 assert_eq!(submit_sm.number_of_dests(), 2);
593 assert_eq!(submit_sm.dest_address().len(), 2);
594
595 let submit_sm = SubmitMulti::<'static, 16>::builder()
596 .push_dest_address(DestAddress::SmeAddress(SmeAddress::new(
597 Ton::International,
598 Npi::Isdn,
599 COctetString::new(b"1234567890123456789\0").unwrap(),
600 )))
601 .unwrap()
602 .push_dest_address(DestAddress::DistributionListName(
603 DistributionListName::new(COctetString::new(b"1234567890123456789\0").unwrap()),
604 ))
605 .unwrap()
606 .clear_dest_address()
607 .build();
608
609 assert_eq!(submit_sm.number_of_dests(), 0);
610 assert!(submit_sm.dest_address().is_empty());
611 }
612}