rusmpp_core/pdus/owned/
submit_multi.rs

1use rusmpp_macros::Rusmpp;
2
3use crate::{
4    encode::Length,
5    pdus::owned::Pdu,
6    tlvs::owned::{MessageSubmissionRequestTlvValue, Tlv},
7    types::owned::{COctetString, EmptyOrFullCOctetString, OctetString},
8    values::{owned::*, *},
9};
10
11#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Rusmpp)]
12#[rusmpp(decode = owned, test = skip)]
13#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
14#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
15#[cfg_attr(feature = "serde-deserialize-unchecked", derive(::serde::Deserialize))]
16pub struct SubmitMulti {
17    /// The service_type parameter can be used to indicate the
18    /// SMS Application service associated with the message.
19    /// Specifying the service_type allows the ESME to avail of
20    /// enhanced messaging services such as “replace by
21    /// service_type” or control the teleservice used on the air
22    /// interface.
23    ///
24    /// Set to NULL for default MC settings.
25    pub service_type: ServiceType,
26    /// Type of Number for source address.
27    ///
28    /// If not known, set to NULL (Unknown).
29    pub source_addr_ton: Ton,
30    /// Numbering Plan Indicator for source address.
31    ///
32    /// If not known, set to NULL (Unknown).
33    pub source_addr_npi: Npi,
34    /// Address of SME which originated this message.
35    ///
36    /// If not known, set to NULL (Unknown).
37    pub source_addr: COctetString<1, 21>,
38    /// Number of destination addresses – indicates the
39    /// number of destinations that are to follow.
40    ///
41    /// A maximum of 255 destination addresses are allowed.
42    ///
43    /// Note: Set to 1 when submitting to one SME Address or when
44    /// submitting to one Distribution List.
45    number_of_dests: u8,
46    /// Composite field.
47    #[rusmpp(count = number_of_dests)]
48    dest_address: alloc::vec::Vec<DestAddress>,
49    /// Indicates Message Mode and Message Type.
50    pub esm_class: EsmClass,
51    /// Protocol Identifier.
52    ///
53    /// Network specific field.
54    pub protocol_id: u8,
55    /// Designates the priority level of the message.
56    pub priority_flag: PriorityFlag,
57    /// The short message is to be scheduled by the MC for delivery.
58    ///
59    /// Set to NULL for immediate message delivery.
60    pub schedule_delivery_time: EmptyOrFullCOctetString<17>,
61    /// The validity period of this message.
62    ///
63    /// Set to NULL to request the SMSC default validity period.
64    ///
65    /// Note: this is superseded by the qos_time_to_live TLV if specified.
66    pub validity_period: EmptyOrFullCOctetString<17>,
67    /// Indicator to signify if a MC delivery receipt or an SME
68    /// acknowledgement is required.
69    pub registered_delivery: RegisteredDelivery,
70    /// Flag indicating if submitted message should replace an
71    /// existing message.
72    pub replace_if_present_flag: ReplaceIfPresentFlag,
73    /// Defines the encoding scheme of the short message user data.
74    pub data_coding: DataCoding,
75    /// Indicates the short message to send from a list of pre- defined
76    /// (‘canned’) short messages stored on the MC.
77    ///
78    /// If not using a MC canned message, set to NULL.
79    pub sm_default_msg_id: u8,
80    /// Length in octets of the short_message user data.
81    sm_length: u8,
82    /// Up to 255 octets of short message user data.
83    ///
84    /// The exact physical limit for short_message size may
85    /// vary according to the underlying network
86    ///
87    /// Note: this field is superceded by the message_payload TLV if
88    /// specified.
89    ///
90    /// Applications which need to send messages longer than
91    /// 255 octets should use the message_payload TLV. In
92    /// this case the sm_length field should be set to zero.
93    #[rusmpp(length = sm_length)]
94    short_message: OctetString<0, 255>,
95    /// Message submission request TLVs ([`MessageSubmissionRequestTlvValue`]).
96    #[rusmpp(length = "unchecked")]
97    tlvs: alloc::vec::Vec<Tlv>,
98}
99
100impl SubmitMulti {
101    #[allow(clippy::too_many_arguments)]
102    pub fn new(
103        service_type: ServiceType,
104        source_addr_ton: Ton,
105        source_addr_npi: Npi,
106        source_addr: COctetString<1, 21>,
107        dest_address: alloc::vec::Vec<DestAddress>,
108        esm_class: EsmClass,
109        protocol_id: u8,
110        priority_flag: PriorityFlag,
111        schedule_delivery_time: EmptyOrFullCOctetString<17>,
112        validity_period: EmptyOrFullCOctetString<17>,
113        registered_delivery: RegisteredDelivery,
114        replace_if_present_flag: ReplaceIfPresentFlag,
115        data_coding: DataCoding,
116        sm_default_msg_id: u8,
117        short_message: OctetString<0, 255>,
118        tlvs: alloc::vec::Vec<MessageSubmissionRequestTlvValue>,
119    ) -> Self {
120        let sm_length = short_message.length() as u8;
121        let number_of_dests = dest_address.len() as u8;
122
123        let tlvs = tlvs.into_iter().map(From::from).collect();
124
125        Self {
126            service_type,
127            source_addr_ton,
128            source_addr_npi,
129            source_addr,
130            number_of_dests,
131            dest_address,
132            esm_class,
133            protocol_id,
134            priority_flag,
135            schedule_delivery_time,
136            validity_period,
137            registered_delivery,
138            replace_if_present_flag,
139            data_coding,
140            sm_default_msg_id,
141            sm_length,
142            short_message,
143            tlvs,
144        }
145    }
146
147    pub const fn number_of_dests(&self) -> u8 {
148        self.number_of_dests
149    }
150
151    pub fn dest_address(&self) -> &[DestAddress] {
152        &self.dest_address
153    }
154
155    pub fn set_dest_address(&mut self, dest_address: alloc::vec::Vec<DestAddress>) {
156        self.dest_address = dest_address;
157        self.number_of_dests = self.dest_address.len() as u8;
158    }
159
160    pub fn push_dest_address(&mut self, dest_address: DestAddress) {
161        self.dest_address.push(dest_address);
162        self.number_of_dests = self.dest_address.len() as u8;
163    }
164
165    pub fn clear_dest_address(&mut self) {
166        self.dest_address.clear();
167        self.number_of_dests = self.dest_address.len() as u8;
168    }
169
170    pub const fn sm_length(&self) -> u8 {
171        self.sm_length
172    }
173
174    pub const fn short_message(&self) -> &OctetString<0, 255> {
175        &self.short_message
176    }
177
178    /// Sets the `short_message` and `sm_length`.
179    ///
180    /// # Note
181    ///
182    /// `short_message` is superceded by [`TlvValue::MessagePayload`](crate::tlvs::owned::TlvValue::MessagePayload) and should only be used if
183    /// [`TlvValue::MessagePayload`](crate::tlvs::owned::TlvValue::MessagePayload) is not present.
184    pub fn set_short_message(&mut self, short_message: OctetString<0, 255>) {
185        self.short_message = short_message;
186        self.sm_length = self.short_message.length() as u8;
187    }
188
189    pub fn tlvs(&self) -> &[Tlv] {
190        &self.tlvs
191    }
192
193    pub fn set_tlvs(&mut self, tlvs: alloc::vec::Vec<MessageSubmissionRequestTlvValue>) {
194        self.tlvs = tlvs.into_iter().map(From::from).collect();
195    }
196
197    pub fn clear_tlvs(&mut self) {
198        self.tlvs.clear();
199    }
200
201    pub fn push_tlv(&mut self, tlv: impl Into<MessageSubmissionRequestTlvValue>) {
202        self.tlvs.push(Tlv::from(tlv.into()));
203    }
204
205    pub fn builder() -> SubmitMultiBuilder {
206        SubmitMultiBuilder::new()
207    }
208}
209
210impl From<SubmitMulti> for Pdu {
211    fn from(value: SubmitMulti) -> Self {
212        Self::SubmitMulti(value)
213    }
214}
215
216#[derive(Debug, Default)]
217pub struct SubmitMultiBuilder {
218    inner: SubmitMulti,
219}
220
221impl SubmitMultiBuilder {
222    pub fn new() -> Self {
223        Default::default()
224    }
225
226    pub fn service_type(mut self, service_type: ServiceType) -> Self {
227        self.inner.service_type = service_type;
228        self
229    }
230
231    pub fn source_addr_ton(mut self, source_addr_ton: Ton) -> Self {
232        self.inner.source_addr_ton = source_addr_ton;
233        self
234    }
235
236    pub fn source_addr_npi(mut self, source_addr_npi: Npi) -> Self {
237        self.inner.source_addr_npi = source_addr_npi;
238        self
239    }
240
241    pub fn source_addr(mut self, source_addr: COctetString<1, 21>) -> Self {
242        self.inner.source_addr = source_addr;
243        self
244    }
245
246    pub fn dest_address(mut self, dest_address: alloc::vec::Vec<DestAddress>) -> Self {
247        self.inner.set_dest_address(dest_address);
248        self
249    }
250
251    pub fn push_dest_address(mut self, dest_address: DestAddress) -> Self {
252        self.inner.push_dest_address(dest_address);
253        self
254    }
255
256    pub fn clear_dest_address(mut self) -> Self {
257        self.inner.clear_dest_address();
258        self
259    }
260
261    pub fn esm_class(mut self, esm_class: EsmClass) -> Self {
262        self.inner.esm_class = esm_class;
263        self
264    }
265
266    pub fn protocol_id(mut self, protocol_id: u8) -> Self {
267        self.inner.protocol_id = protocol_id;
268        self
269    }
270
271    pub fn priority_flag(mut self, priority_flag: PriorityFlag) -> Self {
272        self.inner.priority_flag = priority_flag;
273        self
274    }
275
276    pub fn schedule_delivery_time(
277        mut self,
278        schedule_delivery_time: EmptyOrFullCOctetString<17>,
279    ) -> Self {
280        self.inner.schedule_delivery_time = schedule_delivery_time;
281        self
282    }
283
284    pub fn validity_period(mut self, validity_period: EmptyOrFullCOctetString<17>) -> Self {
285        self.inner.validity_period = validity_period;
286        self
287    }
288
289    pub fn registered_delivery(mut self, registered_delivery: RegisteredDelivery) -> Self {
290        self.inner.registered_delivery = registered_delivery;
291        self
292    }
293
294    pub fn replace_if_present_flag(
295        mut self,
296        replace_if_present_flag: ReplaceIfPresentFlag,
297    ) -> Self {
298        self.inner.replace_if_present_flag = replace_if_present_flag;
299        self
300    }
301
302    pub fn data_coding(mut self, data_coding: DataCoding) -> Self {
303        self.inner.data_coding = data_coding;
304        self
305    }
306
307    pub fn sm_default_msg_id(mut self, sm_default_msg_id: u8) -> Self {
308        self.inner.sm_default_msg_id = sm_default_msg_id;
309        self
310    }
311
312    pub fn short_message(mut self, short_message: OctetString<0, 255>) -> Self {
313        self.inner.set_short_message(short_message);
314        self
315    }
316
317    pub fn tlvs(mut self, tlvs: alloc::vec::Vec<MessageSubmissionRequestTlvValue>) -> 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) -> SubmitMulti {
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 SubmitMulti {
346        fn instances() -> alloc::vec::Vec<Self> {
347            alloc::vec![
348                Self::default(),
349                Self::builder()
350                    .service_type(ServiceType::default())
351                    .source_addr_ton(Ton::International)
352                    .source_addr_npi(Npi::Isdn)
353                    .source_addr(COctetString::from_str("Source Address").unwrap())
354                    .esm_class(EsmClass::default())
355                    .protocol_id(0)
356                    .priority_flag(PriorityFlag::default())
357                    .schedule_delivery_time(EmptyOrFullCOctetString::empty())
358                    .validity_period(EmptyOrFullCOctetString::empty())
359                    .registered_delivery(RegisteredDelivery::default())
360                    .replace_if_present_flag(ReplaceIfPresentFlag::default())
361                    .data_coding(DataCoding::default())
362                    .sm_default_msg_id(0)
363                    .short_message(OctetString::from_static_slice(b"Short Message").unwrap())
364                    .build(),
365                Self::builder()
366                    .short_message(OctetString::from_static_slice(b"Short Message").unwrap())
367                    .push_tlv(MessageSubmissionRequestTlvValue::MessagePayload(
368                        MessagePayload::new(AnyOctetString::from_static_slice(b"Message Payload")),
369                    ))
370                    .build(),
371                Self::builder()
372                    .push_dest_address(DestAddress::SmeAddress(SmeAddress::new(
373                        Ton::International,
374                        Npi::Isdn,
375                        COctetString::from_static_slice(b"1234567890123456789\0").unwrap(),
376                    )))
377                    .push_dest_address(DestAddress::DistributionListName(
378                        DistributionListName::new(
379                            COctetString::from_static_slice(b"1234567890123456789\0").unwrap(),
380                        ),
381                    ))
382                    .short_message(OctetString::from_static_slice(b"Short Message").unwrap())
383                    .push_tlv(MessageSubmissionRequestTlvValue::MessagePayload(
384                        MessagePayload::new(AnyOctetString::from_static_slice(b"Message Payload")),
385                    ))
386                    .push_tlv(MessageSubmissionRequestTlvValue::DestTelematicsId(16))
387                    .build(),
388            ]
389        }
390    }
391
392    #[test]
393    fn encode_decode() {
394        crate::tests::owned::encode_decode_with_length_test_instances::<SubmitMulti>();
395    }
396
397    #[test]
398    fn short_message_length() {
399        let short_message = OctetString::from_static_slice(b"Short Message").unwrap();
400
401        let submit_sm = SubmitMulti::builder()
402            .short_message(short_message.clone())
403            .build();
404
405        assert_eq!(submit_sm.short_message(), &short_message);
406        assert_eq!(submit_sm.sm_length(), short_message.length() as u8);
407    }
408
409    #[test]
410    fn count() {
411        let submit_multi = SubmitMulti::default();
412
413        assert_eq!(submit_multi.number_of_dests(), 0);
414        assert!(submit_multi.dest_address().is_empty());
415
416        let submit_sm = SubmitMulti::builder()
417            .dest_address(alloc::vec![
418                DestAddress::SmeAddress(SmeAddress::new(
419                    Ton::International,
420                    Npi::Isdn,
421                    COctetString::from_static_slice(b"1234567890123456789\0").unwrap(),
422                )),
423                DestAddress::DistributionListName(DistributionListName::new(
424                    COctetString::from_static_slice(b"1234567890123456789\0").unwrap(),
425                )),
426            ])
427            .build();
428
429        assert_eq!(submit_sm.number_of_dests(), 2);
430        assert_eq!(submit_sm.dest_address().len(), 2);
431
432        let submit_sm = SubmitMulti::builder()
433            .push_dest_address(DestAddress::SmeAddress(SmeAddress::new(
434                Ton::International,
435                Npi::Isdn,
436                COctetString::from_static_slice(b"1234567890123456789\0").unwrap(),
437            )))
438            .push_dest_address(DestAddress::DistributionListName(
439                DistributionListName::new(
440                    COctetString::from_static_slice(b"1234567890123456789\0").unwrap(),
441                ),
442            ))
443            .build();
444
445        assert_eq!(submit_sm.number_of_dests(), 2);
446        assert_eq!(submit_sm.dest_address().len(), 2);
447
448        let submit_sm = SubmitMulti::builder()
449            .push_dest_address(DestAddress::SmeAddress(SmeAddress::new(
450                Ton::International,
451                Npi::Isdn,
452                COctetString::from_static_slice(b"1234567890123456789\0").unwrap(),
453            )))
454            .push_dest_address(DestAddress::DistributionListName(
455                DistributionListName::new(
456                    COctetString::from_static_slice(b"1234567890123456789\0").unwrap(),
457                ),
458            ))
459            .clear_dest_address()
460            .build();
461
462        assert_eq!(submit_sm.number_of_dests(), 0);
463        assert!(submit_sm.dest_address().is_empty());
464    }
465}