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