rusmpp_core/pdus/borrowed/
deliver_sm.rs

1use rusmpp_macros::Rusmpp;
2
3use crate::{
4    encode::Length,
5    pdus::borrowed::Pdu,
6    tlvs::{
7        TlvTag,
8        borrowed::{MessageDeliveryRequestTlvValue, Tlv},
9    },
10    types::borrowed::{COctetString, EmptyOrFullCOctetString, OctetString},
11    values::{borrowed::*, *},
12};
13
14/// This operation is used by an ESME to submit a short message to the MC for onward
15/// transmission to a specified short message entity (SME).
16#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Rusmpp)]
17#[rusmpp(decode = borrowed, test = skip)]
18#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
19#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
20pub struct DeliverSm<'a, const N: usize> {
21    /// The service_type parameter can be used to
22    /// indicate the SMS Application service
23    /// associated with the message. Specifying the
24    /// service_type allows the ESME to avail of enhanced
25    /// messaging services such as “replace by service_type”
26    /// or to control the teleservice used on the
27    /// air interface.
28    ///
29    /// Set to NULL for default MC settings.
30    pub service_type: ServiceType<'a>,
31    /// Type of Number for source address.
32    pub source_addr_ton: Ton,
33    /// Numbering Plan Indicator for source address.
34    pub source_addr_npi: Npi,
35    /// Address of SME which originated this message.
36    pub source_addr: COctetString<'a, 1, 21>,
37    /// Type of Number for destination.
38    pub dest_addr_ton: Ton,
39    /// Numbering Plan Indicator for destination.
40    pub dest_addr_npi: Npi,
41    /// Destination address of this
42    /// short message For mobile
43    /// terminated messages, this
44    /// is the directory number of
45    /// the recipient MS
46    pub destination_addr: COctetString<'a, 1, 21>,
47    /// Indicates Message Mode
48    /// and Message Type.
49    pub esm_class: EsmClass,
50    /// Protocol Identifier.
51    /// Network specific field.
52    pub protocol_id: u8,
53    /// Designates the priority level of the message.
54    pub priority_flag: PriorityFlag,
55    /// The short message is to be
56    /// scheduled by the MC for delivery.
57    ///
58    /// Set to NULL for immediate message delivery.
59    pub schedule_delivery_time: EmptyOrFullCOctetString<'a, 17>,
60    /// The validity period of this message.
61    ///
62    /// Set to NULL to request the MC default validity period.
63    ///
64    /// Note: this is superseded by the qos_time_to_live TLV if
65    /// specified.
66    pub validity_period: EmptyOrFullCOctetString<'a, 17>,
67    /// Indicator to signify if a MC delivery receipt, manual
68    /// ACK, delivery ACK or an intermediate notification is required.
69    pub registered_delivery: RegisteredDelivery,
70    /// Flag indicating if the submitted message should replace an existing message.
71    pub replace_if_present_flag: ReplaceIfPresentFlag,
72    // Defines the encoding scheme of the short message user data.
73    pub data_coding: DataCoding,
74    /// Indicates the short message to send from a list of pre- defined (‘canned’)
75    /// short messages stored on the MC. If not using a MC canned message, set to NULL.
76    pub sm_default_msg_id: u8,
77    /// Length in octets of the short_message user data.
78    sm_length: u8,
79    /// Up to 255 octets of short message user data.
80    ///
81    /// The exact physical limit for short_message size may
82    /// vary according to the underlying network
83    ///
84    /// Note: this field is superceded by the message_payload TLV if
85    /// specified.
86    #[rusmpp(length = sm_length)]
87    short_message: OctetString<'a, 0, 255>,
88    /// Message delivery request TLVs ([`MessageDeliveryRequestTlvValue`])
89    #[rusmpp(length = "unchecked")]
90    #[cfg_attr(feature = "arbitrary", arbitrary(default))]
91    tlvs: heapless::vec::Vec<Tlv<'a>, N>,
92}
93
94impl<'a, const N: usize> DeliverSm<'a, N> {
95    #[allow(clippy::too_many_arguments)]
96    pub fn new(
97        service_type: ServiceType<'a>,
98        source_addr_ton: Ton,
99        source_addr_npi: Npi,
100        source_addr: COctetString<'a, 1, 21>,
101        dest_addr_ton: Ton,
102        dest_addr_npi: Npi,
103        destination_addr: COctetString<'a, 1, 21>,
104        esm_class: EsmClass,
105        protocol_id: u8,
106        priority_flag: PriorityFlag,
107        schedule_delivery_time: EmptyOrFullCOctetString<'a, 17>,
108        validity_period: EmptyOrFullCOctetString<'a, 17>,
109        registered_delivery: RegisteredDelivery,
110        replace_if_present_flag: ReplaceIfPresentFlag,
111        data_coding: DataCoding,
112        sm_default_msg_id: u8,
113        short_message: OctetString<'a, 0, 255>,
114        tlvs: heapless::vec::Vec<impl Into<MessageDeliveryRequestTlvValue<'a>>, N>,
115    ) -> Self {
116        let tlvs = tlvs.into_iter().map(Into::into).map(From::from).collect();
117
118        let sm_length = short_message.length() as u8;
119
120        let mut submit_sm = Self {
121            service_type,
122            source_addr_ton,
123            source_addr_npi,
124            source_addr,
125            dest_addr_ton,
126            dest_addr_npi,
127            destination_addr,
128            esm_class,
129            protocol_id,
130            priority_flag,
131            schedule_delivery_time,
132            validity_period,
133            registered_delivery,
134            replace_if_present_flag,
135            data_coding,
136            sm_default_msg_id,
137            sm_length,
138            short_message,
139            tlvs,
140        };
141
142        submit_sm.clear_short_message_if_message_payload_exists();
143
144        submit_sm
145    }
146
147    pub const fn sm_length(&self) -> u8 {
148        self.sm_length
149    }
150
151    pub fn short_message(&self) -> &OctetString<'a, 0, 255> {
152        &self.short_message
153    }
154
155    /// Sets the short message and short message length.
156    /// Updates the short message and short message length accordingly.
157    /// Has no effect if the message payload is set.
158    /// Returns true if the short message and short message length were set.
159    pub fn set_short_message(&mut self, short_message: OctetString<'a, 0, 255>) -> bool {
160        self.short_message = short_message;
161        self.sm_length = self.short_message.length() as u8;
162
163        !self.clear_short_message_if_message_payload_exists()
164    }
165
166    pub fn tlvs(&'_ self) -> &'_ [Tlv<'_>] {
167        &self.tlvs
168    }
169
170    pub fn set_tlvs(
171        &mut self,
172        tlvs: heapless::vec::Vec<impl Into<MessageDeliveryRequestTlvValue<'a>>, N>,
173    ) {
174        self.tlvs = tlvs.into_iter().map(Into::into).map(From::from).collect();
175
176        self.clear_short_message_if_message_payload_exists();
177    }
178
179    pub fn clear_tlvs(&mut self) {
180        self.tlvs.clear();
181    }
182
183    pub fn push_tlv(
184        &mut self,
185        tlv: impl Into<MessageDeliveryRequestTlvValue<'a>>,
186    ) -> Result<(), Tlv<'a>> {
187        self.tlvs.push(Tlv::from(tlv.into()))?;
188
189        self.clear_short_message_if_message_payload_exists();
190
191        Ok(())
192    }
193
194    /// Clears the short message and short message length if the message payload is set.
195    /// Returns true if the short message and short message length were cleared.
196    fn clear_short_message_if_message_payload_exists(&mut self) -> bool {
197        let message_payload_exists = self
198            .tlvs
199            .iter()
200            .any(|value| matches!(value.tag(), TlvTag::MessagePayload));
201
202        if message_payload_exists {
203            self.short_message = OctetString::empty();
204            self.sm_length = 0;
205
206            return true;
207        };
208
209        false
210    }
211
212    pub fn builder() -> DeliverSmBuilder<'a, N> {
213        DeliverSmBuilder::new()
214    }
215}
216
217impl<'a, const N: usize> From<DeliverSm<'a, N>> for Pdu<'a, N> {
218    fn from(value: DeliverSm<'a, N>) -> Self {
219        Self::DeliverSm(value)
220    }
221}
222
223#[derive(Debug, Default)]
224pub struct DeliverSmBuilder<'a, const N: usize> {
225    inner: DeliverSm<'a, N>,
226}
227
228impl<'a, const N: usize> DeliverSmBuilder<'a, N> {
229    pub fn new() -> Self {
230        Self::default()
231    }
232
233    pub fn service_type(mut self, service_type: ServiceType<'a>) -> Self {
234        self.inner.service_type = service_type;
235        self
236    }
237
238    pub fn source_addr_ton(mut self, source_addr_ton: Ton) -> Self {
239        self.inner.source_addr_ton = source_addr_ton;
240        self
241    }
242
243    pub fn source_addr_npi(mut self, source_addr_npi: Npi) -> Self {
244        self.inner.source_addr_npi = source_addr_npi;
245        self
246    }
247
248    pub fn source_addr(mut self, source_addr: COctetString<'a, 1, 21>) -> Self {
249        self.inner.source_addr = source_addr;
250        self
251    }
252
253    pub fn dest_addr_ton(mut self, dest_addr_ton: Ton) -> Self {
254        self.inner.dest_addr_ton = dest_addr_ton;
255        self
256    }
257
258    pub fn dest_addr_npi(mut self, dest_addr_npi: Npi) -> Self {
259        self.inner.dest_addr_npi = dest_addr_npi;
260        self
261    }
262
263    pub fn destination_addr(mut self, destination_addr: COctetString<'a, 1, 21>) -> Self {
264        self.inner.destination_addr = destination_addr;
265        self
266    }
267
268    pub fn esm_class(mut self, esm_class: EsmClass) -> Self {
269        self.inner.esm_class = esm_class;
270        self
271    }
272
273    pub fn protocol_id(mut self, protocol_id: u8) -> Self {
274        self.inner.protocol_id = protocol_id;
275        self
276    }
277
278    pub fn priority_flag(mut self, priority_flag: PriorityFlag) -> Self {
279        self.inner.priority_flag = priority_flag;
280        self
281    }
282
283    pub fn schedule_delivery_time(
284        mut self,
285        schedule_delivery_time: EmptyOrFullCOctetString<'a, 17>,
286    ) -> Self {
287        self.inner.schedule_delivery_time = schedule_delivery_time;
288        self
289    }
290
291    pub fn validity_period(mut self, validity_period: EmptyOrFullCOctetString<'a, 17>) -> Self {
292        self.inner.validity_period = validity_period;
293        self
294    }
295
296    pub fn registered_delivery(mut self, registered_delivery: RegisteredDelivery) -> Self {
297        self.inner.registered_delivery = registered_delivery;
298        self
299    }
300
301    pub fn replace_if_present_flag(
302        mut self,
303        replace_if_present_flag: ReplaceIfPresentFlag,
304    ) -> Self {
305        self.inner.replace_if_present_flag = replace_if_present_flag;
306        self
307    }
308
309    pub fn data_coding(mut self, data_coding: DataCoding) -> Self {
310        self.inner.data_coding = data_coding;
311        self
312    }
313
314    pub fn sm_default_msg_id(mut self, sm_default_msg_id: u8) -> Self {
315        self.inner.sm_default_msg_id = sm_default_msg_id;
316        self
317    }
318
319    pub fn short_message(mut self, short_message: OctetString<'a, 0, 255>) -> Self {
320        self.inner.set_short_message(short_message);
321        self
322    }
323
324    pub fn tlvs(
325        mut self,
326        tlvs: heapless::vec::Vec<impl Into<MessageDeliveryRequestTlvValue<'a>>, N>,
327    ) -> Self {
328        self.inner.set_tlvs(tlvs);
329        self
330    }
331
332    pub fn clear_tlvs(mut self) -> Self {
333        self.inner.clear_tlvs();
334        self
335    }
336
337    pub fn push_tlv(
338        mut self,
339        tlv: impl Into<MessageDeliveryRequestTlvValue<'a>>,
340    ) -> Result<Self, Tlv<'a>> {
341        self.inner.push_tlv(tlv)?;
342        Ok(self)
343    }
344
345    pub fn build(self) -> DeliverSm<'a, N> {
346        self.inner
347    }
348}
349
350#[cfg(test)]
351mod tests {
352    use crate::{tests::TestInstance, types::borrowed::AnyOctetString};
353
354    use super::*;
355
356    impl<const N: usize> TestInstance for DeliverSm<'_, N> {
357        fn instances() -> alloc::vec::Vec<Self> {
358            alloc::vec![
359                Self::default(),
360                Self::builder()
361                    .source_addr_ton(Ton::International)
362                    .source_addr_npi(Npi::Isdn)
363                    .source_addr(COctetString::new(b"Source Address\0").unwrap())
364                    .dest_addr_ton(Ton::International)
365                    .dest_addr_npi(Npi::Isdn)
366                    .destination_addr(COctetString::new(b"Destination Address\0").unwrap())
367                    .schedule_delivery_time(EmptyOrFullCOctetString::empty())
368                    .validity_period(EmptyOrFullCOctetString::empty())
369                    .registered_delivery(RegisteredDelivery::default())
370                    .replace_if_present_flag(ReplaceIfPresentFlag::Replace)
371                    .short_message(OctetString::new(b"Short Message").unwrap())
372                    .build(),
373                Self::builder()
374                    .source_addr_ton(Ton::International)
375                    .source_addr_npi(Npi::Isdn)
376                    .source_addr(COctetString::new(b"Source Address\0").unwrap())
377                    .dest_addr_ton(Ton::International)
378                    .dest_addr_npi(Npi::Isdn)
379                    .destination_addr(COctetString::new(b"Destination Address\0").unwrap())
380                    .protocol_id(0)
381                    .schedule_delivery_time(EmptyOrFullCOctetString::empty())
382                    .validity_period(EmptyOrFullCOctetString::empty())
383                    .registered_delivery(RegisteredDelivery::default())
384                    .replace_if_present_flag(ReplaceIfPresentFlag::Replace)
385                    .data_coding(DataCoding::default())
386                    .sm_default_msg_id(0)
387                    .short_message(OctetString::new(b"Short Message").unwrap())
388                    .tlvs(
389                        [
390                            MessageDeliveryRequestTlvValue::MessagePayload(MessagePayload::new(
391                                AnyOctetString::new(b"Message Payload"),
392                            )),
393                            MessageDeliveryRequestTlvValue::MessagePayload(MessagePayload::new(
394                                AnyOctetString::new(b"Message Payload 2"),
395                            )),
396                            MessageDeliveryRequestTlvValue::CallbackNumPresInd(
397                                CallbackNumPresInd::new(
398                                    Presentation::NumberNotAvailable,
399                                    Screening::VerifiedAndPassed,
400                                ),
401                            ),
402                        ]
403                        .into()
404                    )
405                    .build(),
406            ]
407        }
408    }
409
410    #[test]
411    fn encode_decode() {
412        crate::tests::borrowed::encode_decode_with_length_test_instances::<DeliverSm<'static, 16>>(
413        );
414    }
415
416    #[test]
417    fn short_message_length() {
418        let short_message = OctetString::new(b"Short Message").unwrap();
419
420        let submit_sm = DeliverSm::<'static, 16>::builder()
421            .short_message(short_message.clone())
422            .build();
423
424        assert_eq!(submit_sm.short_message(), &short_message);
425        assert_eq!(submit_sm.sm_length(), short_message.length() as u8);
426    }
427
428    #[test]
429    fn short_message_override() {
430        let short_message_1 = OctetString::new(b"Short Message 101").unwrap();
431        let short_message_2 = OctetString::new(b"Short Message 2").unwrap();
432
433        let submit_sm = DeliverSm::<'static, 16>::builder()
434            .short_message(short_message_1)
435            .short_message(short_message_2.clone())
436            .build();
437
438        assert_eq!(submit_sm.short_message(), &short_message_2);
439        assert_eq!(submit_sm.sm_length(), short_message_2.length() as u8);
440    }
441
442    #[test]
443    fn message_payload_suppresses_short_message() {
444        let short_message = OctetString::new(b"Short Message").unwrap();
445        let message_payload = MessagePayload::new(AnyOctetString::new(b"Message Payload"));
446
447        // Using push_tlv
448        let deliver_sm = DeliverSm::<'static, 16>::builder()
449            .short_message(short_message.clone())
450            .push_tlv(MessageDeliveryRequestTlvValue::MessagePayload(
451                message_payload.clone(),
452            ))
453            .unwrap()
454            .build();
455
456        assert_eq!(deliver_sm.short_message(), &OctetString::empty());
457        assert_eq!(deliver_sm.sm_length(), 0);
458
459        // Using tlvs
460        let submit_sm = DeliverSm::<'static, 16>::builder()
461            .short_message(short_message.clone())
462            .tlvs(
463                [MessageDeliveryRequestTlvValue::MessagePayload(
464                    message_payload.clone(),
465                )]
466                .into(),
467            )
468            .build();
469
470        assert_eq!(submit_sm.short_message(), &OctetString::empty());
471        assert_eq!(submit_sm.sm_length(), 0);
472
473        // Even setting the short message after the message payload should not set the short message
474        // Using push_tlv
475        let submit_sm = DeliverSm::<'static, 16>::builder()
476            .short_message(short_message.clone())
477            .push_tlv(MessageDeliveryRequestTlvValue::MessagePayload(
478                message_payload.clone(),
479            ))
480            .unwrap()
481            .short_message(short_message.clone())
482            .build();
483
484        assert_eq!(submit_sm.short_message(), &OctetString::empty());
485        assert_eq!(submit_sm.sm_length(), 0);
486
487        // Using tlvs
488        let submit_sm = DeliverSm::<'static, 16>::builder()
489            .short_message(short_message.clone())
490            .tlvs(
491                [MessageDeliveryRequestTlvValue::MessagePayload(
492                    message_payload.clone(),
493                )]
494                .into(),
495            )
496            .short_message(short_message.clone())
497            .build();
498
499        assert_eq!(submit_sm.short_message(), &OctetString::empty());
500        assert_eq!(submit_sm.sm_length(), 0);
501
502        // Removing the message payload and then setting the short message should set the short message
503        let submit_sm = DeliverSm::<'static, 16>::builder()
504            .push_tlv(MessageDeliveryRequestTlvValue::MessagePayload(
505                message_payload.clone(),
506            ))
507            .unwrap()
508            .clear_tlvs()
509            .short_message(short_message.clone())
510            .build();
511
512        assert_eq!(submit_sm.short_message(), &short_message);
513        assert_eq!(submit_sm.sm_length(), short_message.length() as u8);
514    }
515}