rusmpp_core/pdus/owned/
deliver_sm.rs

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